Merging events framework branch into master. This commit will bring
following changes

   - introduced notion of event bus with publish, subscribe, unsubscribe
     semantics

   - a plug-in can implement the EventBus abstraction to provide event
     bug to CloudStack

   - A rabbitMQ based plug-in that can interact with AMQP servers to
     provide message broker based event-bug

   - stream lines, action events, usage events, alerts publishing in to
     convineance classed which are also used to publish corresponding
     event on to event bus

   - introduced notion of state change event. On a state change, in the
     state machine corrsponding to the resource, a state change event is
     published on the event bug

   - associated a state machined with Snapshot and Network objects

   - Virtual Machine, Volume, Snaphost, Network object state changes wil
     result in a state change event
diff --git a/api/src/com/cloud/event/EventCategory.java b/api/src/com/cloud/event/EventCategory.java
new file mode 100644
index 0000000..cee6529
--- /dev/null
+++ b/api/src/com/cloud/event/EventCategory.java
@@ -0,0 +1,55 @@
+/*
+ * 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.
+ */
+
+package com.cloud.event;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class EventCategory {
+    private static List<EventCategory> eventCategories = new ArrayList<EventCategory>();
+    private String eventCategoryName;
+
+    public  EventCategory(String categoryName) {
+        this.eventCategoryName = categoryName;
+        eventCategories.add(this);
+    }
+
+    public String getName() {
+        return eventCategoryName;
+    }
+
+    public static List<EventCategory> listAllEventCategories() {
+        return eventCategories;
+    }
+
+    public static EventCategory getEventCategory(String categoryName) {
+        for (EventCategory category : eventCategories) {
+            if (category.getName().equalsIgnoreCase(categoryName)) {
+                return category;
+            }
+        }
+        return null;
+    }
+
+    public static final EventCategory ACTION_EVENT = new EventCategory("ActionEvent");
+    public static final EventCategory ALERT_EVENT  = new EventCategory("AlertEvent");
+    public static final EventCategory USAGE_EVENT  = new EventCategory("UsageEvent");
+    public static final EventCategory RESOURCE_STATE_CHANGE_EVENT = new EventCategory("ResourceStateEvent");
+}
diff --git a/api/src/com/cloud/event/EventTypes.java b/api/src/com/cloud/event/EventTypes.java
index d666c1e..0dd97cb 100755
--- a/api/src/com/cloud/event/EventTypes.java
+++ b/api/src/com/cloud/event/EventTypes.java
@@ -16,7 +16,41 @@
 // under the License.
 package com.cloud.event;
 
+import com.cloud.configuration.Configuration;
+import com.cloud.dc.DataCenter;
+import com.cloud.dc.Pod;
+import com.cloud.dc.StorageNetworkIpRange;
+import com.cloud.dc.Vlan;
+import com.cloud.domain.Domain;
+import com.cloud.host.Host;
+import com.cloud.network.*;
+import com.cloud.network.as.*;
+import com.cloud.network.router.VirtualRouter;
+import com.cloud.network.rules.LoadBalancer;
+import com.cloud.network.rules.StaticNat;
+import com.cloud.network.security.SecurityGroup;
+import com.cloud.network.vpc.PrivateGateway;
+import com.cloud.network.vpc.StaticRoute;
+import com.cloud.network.vpc.Vpc;
+import com.cloud.offering.DiskOffering;
+import com.cloud.offering.NetworkOffering;
+import com.cloud.offering.ServiceOffering;
+import com.cloud.projects.Project;
+import com.cloud.storage.Snapshot;
+import com.cloud.storage.Volume;
+import com.cloud.template.VirtualMachineTemplate;
+import com.cloud.user.Account;
+import com.cloud.user.User;
+import com.cloud.vm.VirtualMachine;
+
+import java.util.HashMap;
+import java.util.Map;
+
 public class EventTypes {
+
+    //map of Event and corresponding entity for which Event is applicable
+    private static Map<String, String> entityEventDetails = null;
+
     // VM Events
     public static final String EVENT_VM_CREATE = "VM.CREATE";
     public static final String EVENT_VM_DESTROY = "VM.DESTROY";
@@ -319,10 +353,323 @@
     public static final String EVENT_AUTOSCALEVMGROUP_UPDATE = "AUTOSCALEVMGROUP.UPDATE";
     public static final String EVENT_AUTOSCALEVMGROUP_ENABLE = "AUTOSCALEVMGROUP.ENABLE";
     public static final String EVENT_AUTOSCALEVMGROUP_DISABLE = "AUTOSCALEVMGROUP.DISABLE";
-    
+
+
     public static final String EVENT_BAREMETAL_DHCP_SERVER_ADD = "PHYSICAL.DHCP.ADD";
     public static final String EVENT_BAREMETAL_DHCP_SERVER_DELETE = "PHYSICAL.DHCP.DELETE";
-    
     public static final String EVENT_BAREMETAL_PXE_SERVER_ADD = "PHYSICAL.PXE.ADD";
     public static final String EVENT_BAREMETAL_PXE_SERVER_DELETE = "PHYSICAL.PXE.DELETE";
+
+    static {
+
+        // TODO: need a way to force author adding event types to declare the entity details as well, with out braking
+        // current ActionEvent annotation semantics
+
+        entityEventDetails = new HashMap<String, String>();
+
+        entityEventDetails.put(EVENT_VM_CREATE, VirtualMachine.class.getName());
+        entityEventDetails.put(EVENT_VM_DESTROY, VirtualMachine.class.getName());
+        entityEventDetails.put(EVENT_VM_START, VirtualMachine.class.getName());
+        entityEventDetails.put(EVENT_VM_STOP, VirtualMachine.class.getName());
+        entityEventDetails.put(EVENT_VM_REBOOT, VirtualMachine.class.getName());
+        entityEventDetails.put(EVENT_VM_UPDATE, VirtualMachine.class.getName());
+        entityEventDetails.put(EVENT_VM_UPGRADE, VirtualMachine.class.getName());
+        entityEventDetails.put(EVENT_VM_RESETPASSWORD, VirtualMachine.class.getName());
+        entityEventDetails.put(EVENT_VM_MIGRATE, VirtualMachine.class.getName());
+        entityEventDetails.put(EVENT_VM_MOVE, VirtualMachine.class.getName());
+        entityEventDetails.put(EVENT_VM_RESTORE, VirtualMachine.class.getName());
+
+        entityEventDetails.put(EVENT_ROUTER_CREATE, VirtualRouter.class.getName());
+        entityEventDetails.put(EVENT_ROUTER_DESTROY, VirtualRouter.class.getName());
+        entityEventDetails.put(EVENT_ROUTER_START, VirtualRouter.class.getName());
+        entityEventDetails.put(EVENT_ROUTER_STOP, VirtualRouter.class.getName());
+        entityEventDetails.put(EVENT_ROUTER_REBOOT, VirtualRouter.class.getName());
+        entityEventDetails.put(EVENT_ROUTER_HA, VirtualRouter.class.getName());
+        entityEventDetails.put(EVENT_ROUTER_UPGRADE, VirtualRouter.class.getName());
+
+        entityEventDetails.put(EVENT_PROXY_CREATE, "ConsoleProxy");
+        entityEventDetails.put(EVENT_PROXY_DESTROY, "ConsoleProxy");
+        entityEventDetails.put(EVENT_PROXY_START, "ConsoleProxy");
+        entityEventDetails.put(EVENT_PROXY_STOP, "ConsoleProxy");
+        entityEventDetails.put(EVENT_PROXY_REBOOT, "ConsoleProxy");
+        entityEventDetails.put(EVENT_ROUTER_HA, "ConsoleProxy");
+        entityEventDetails.put(EVENT_PROXY_HA, "ConsoleProxy");
+
+        entityEventDetails.put(EVENT_VNC_CONNECT, "VNC");
+        entityEventDetails.put(EVENT_VNC_DISCONNECT, "VNC");
+
+        // Network Events
+        entityEventDetails.put(EVENT_NETWORK_CREATE, Network.class.getName());
+        entityEventDetails.put(EVENT_NETWORK_DELETE, Network.class.getName());
+        entityEventDetails.put(EVENT_NETWORK_UPDATE, Network.class.getName());
+        entityEventDetails.put(EVENT_NETWORK_RESTART, Network.class.getName());
+        entityEventDetails.put(EVENT_NET_IP_ASSIGN, PublicIpAddress.class.getName());
+        entityEventDetails.put(EVENT_NET_IP_RELEASE, PublicIpAddress.class.getName());
+        entityEventDetails.put(EVENT_NET_RULE_ADD, Network.class.getName());
+        entityEventDetails.put(EVENT_NET_RULE_DELETE, Network.class.getName());
+        entityEventDetails.put(EVENT_NET_RULE_MODIFY, Network.class.getName());
+        entityEventDetails.put(EVENT_FIREWALL_OPEN, Network.class.getName());
+        entityEventDetails.put(EVENT_FIREWALL_CLOSE, Network.class.getName());
+
+        // Load Balancers
+        entityEventDetails.put(EVENT_ASSIGN_TO_LOAD_BALANCER_RULE, LoadBalancer.class.getName());
+        entityEventDetails.put(EVENT_REMOVE_FROM_LOAD_BALANCER_RULE, LoadBalancer.class.getName());
+        entityEventDetails.put(EVENT_LOAD_BALANCER_CREATE, LoadBalancer.class.getName());
+        entityEventDetails.put(EVENT_LOAD_BALANCER_DELETE, LoadBalancer.class.getName());
+        entityEventDetails.put(EVENT_LB_STICKINESSPOLICY_CREATE, LoadBalancer.class.getName());
+        entityEventDetails.put(EVENT_LB_STICKINESSPOLICY_DELETE, LoadBalancer.class.getName());
+        entityEventDetails.put(EVENT_LOAD_BALANCER_UPDATE, LoadBalancer.class.getName());
+
+        // Account events
+        entityEventDetails.put(EVENT_ACCOUNT_DISABLE, Account.class.getName());
+        entityEventDetails.put(EVENT_ACCOUNT_CREATE, Account.class.getName());
+        entityEventDetails.put(EVENT_ACCOUNT_DELETE, Account.class.getName());
+        entityEventDetails.put(EVENT_ACCOUNT_MARK_DEFAULT_ZONE, Account.class.getName());
+
+        // UserVO Events
+        entityEventDetails.put(EVENT_USER_LOGIN, User.class.getName());
+        entityEventDetails.put(EVENT_USER_LOGOUT, User.class.getName());
+        entityEventDetails.put(EVENT_USER_CREATE, User.class.getName());
+        entityEventDetails.put(EVENT_USER_DELETE, User.class.getName());
+        entityEventDetails.put(EVENT_USER_DISABLE, User.class.getName());
+        entityEventDetails.put(EVENT_USER_UPDATE, User.class.getName());
+        entityEventDetails.put(EVENT_USER_ENABLE, User.class.getName());
+        entityEventDetails.put(EVENT_USER_LOCK, User.class.getName());
+
+        // Template Events
+        entityEventDetails.put(EVENT_TEMPLATE_CREATE, VirtualMachineTemplate.class.getName());
+        entityEventDetails.put(EVENT_TEMPLATE_DELETE, VirtualMachineTemplate.class.getName());
+        entityEventDetails.put(EVENT_TEMPLATE_UPDATE, VirtualMachineTemplate.class.getName());
+        entityEventDetails.put(EVENT_TEMPLATE_DOWNLOAD_START, VirtualMachineTemplate.class.getName());
+        entityEventDetails.put(EVENT_TEMPLATE_DOWNLOAD_SUCCESS, VirtualMachineTemplate.class.getName());
+        entityEventDetails.put(EVENT_TEMPLATE_DOWNLOAD_FAILED, VirtualMachineTemplate.class.getName());
+        entityEventDetails.put(EVENT_TEMPLATE_COPY, VirtualMachineTemplate.class.getName());
+        entityEventDetails.put(EVENT_TEMPLATE_EXTRACT, VirtualMachineTemplate.class.getName());
+        entityEventDetails.put(EVENT_TEMPLATE_UPLOAD, VirtualMachineTemplate.class.getName());
+        entityEventDetails.put(EVENT_TEMPLATE_CLEANUP, VirtualMachineTemplate.class.getName());
+
+        // Volume Events
+        entityEventDetails.put(EVENT_VOLUME_CREATE, Volume.class.getName());
+        entityEventDetails.put(EVENT_VOLUME_DELETE, Volume.class.getName());
+        entityEventDetails.put(EVENT_VOLUME_ATTACH, Volume.class.getName());
+        entityEventDetails.put(EVENT_VOLUME_DETACH, Volume.class.getName());
+        entityEventDetails.put(EVENT_VOLUME_EXTRACT, Volume.class.getName());
+        entityEventDetails.put(EVENT_VOLUME_UPLOAD, Volume.class.getName());
+        entityEventDetails.put(EVENT_VOLUME_MIGRATE, Volume.class.getName());
+        entityEventDetails.put(EVENT_VOLUME_RESIZE, Volume.class.getName());
+
+        // Domains
+        entityEventDetails.put(EVENT_DOMAIN_CREATE, Domain.class.getName());
+        entityEventDetails.put(EVENT_DOMAIN_DELETE, Domain.class.getName());
+        entityEventDetails.put(EVENT_DOMAIN_UPDATE, Domain.class.getName());
+
+        // Snapshots
+        entityEventDetails.put(EVENT_SNAPSHOT_CREATE, Snapshot.class.getName());
+        entityEventDetails.put(EVENT_SNAPSHOT_DELETE, Snapshot.class.getName());
+        entityEventDetails.put(EVENT_SNAPSHOT_POLICY_CREATE, Snapshot.class.getName());
+        entityEventDetails.put(EVENT_SNAPSHOT_POLICY_UPDATE, Snapshot.class.getName());
+        entityEventDetails.put(EVENT_SNAPSHOT_POLICY_DELETE, Snapshot.class.getName());
+
+        // ISO
+        entityEventDetails.put(EVENT_ISO_CREATE, "Iso");
+        entityEventDetails.put(EVENT_ISO_DELETE, "Iso");
+        entityEventDetails.put(EVENT_ISO_COPY, "Iso");
+        entityEventDetails.put(EVENT_ISO_ATTACH, "Iso");
+        entityEventDetails.put(EVENT_ISO_DETACH, "Iso");
+        entityEventDetails.put(EVENT_ISO_EXTRACT, "Iso");
+        entityEventDetails.put(EVENT_ISO_UPLOAD, "Iso");
+
+        // SSVM
+        entityEventDetails.put(EVENT_SSVM_CREATE, "SecondaryStorageVm");
+        entityEventDetails.put(EVENT_SSVM_DESTROY, "SecondaryStorageVm");
+        entityEventDetails.put(EVENT_SSVM_START, "SecondaryStorageVm");
+        entityEventDetails.put(EVENT_SSVM_STOP, "SecondaryStorageVm");
+        entityEventDetails.put(EVENT_SSVM_REBOOT, "SecondaryStorageVm");
+        entityEventDetails.put(EVENT_SSVM_HA, "SecondaryStorageVm");
+
+        // Service Offerings
+        entityEventDetails.put(EVENT_SERVICE_OFFERING_CREATE, ServiceOffering.class.getName());
+        entityEventDetails.put(EVENT_SERVICE_OFFERING_EDIT, ServiceOffering.class.getName());
+        entityEventDetails.put(EVENT_SERVICE_OFFERING_DELETE, ServiceOffering.class.getName());
+
+        // Disk Offerings
+        entityEventDetails.put(EVENT_DISK_OFFERING_CREATE, DiskOffering.class.getName());
+        entityEventDetails.put(EVENT_DISK_OFFERING_EDIT, DiskOffering.class.getName());
+        entityEventDetails.put(EVENT_DISK_OFFERING_DELETE, DiskOffering.class.getName());
+
+        // Network offerings
+        entityEventDetails.put(EVENT_NETWORK_OFFERING_CREATE, NetworkOffering.class.getName());
+        entityEventDetails.put(EVENT_NETWORK_OFFERING_ASSIGN, NetworkOffering.class.getName());
+        entityEventDetails.put(EVENT_NETWORK_OFFERING_EDIT, NetworkOffering.class.getName());
+        entityEventDetails.put(EVENT_NETWORK_OFFERING_REMOVE, NetworkOffering.class.getName());
+        entityEventDetails.put(EVENT_NETWORK_OFFERING_DELETE, NetworkOffering.class.getName());
+
+        // Pods
+        entityEventDetails.put(EVENT_POD_CREATE, Pod.class.getName());
+        entityEventDetails.put(EVENT_POD_EDIT, Pod.class.getName());
+        entityEventDetails.put(EVENT_POD_DELETE, Pod.class.getName());
+
+        // Zones
+        entityEventDetails.put(EVENT_ZONE_CREATE, DataCenter.class.getName());
+        entityEventDetails.put(EVENT_ZONE_EDIT, DataCenter.class.getName());
+        entityEventDetails.put(EVENT_ZONE_DELETE, DataCenter.class.getName());
+
+        // VLANs/IP ranges
+        entityEventDetails.put(EVENT_VLAN_IP_RANGE_CREATE, Vlan.class.getName());
+        entityEventDetails.put(EVENT_VLAN_IP_RANGE_DELETE,Vlan.class.getName());
+
+        entityEventDetails.put(EVENT_STORAGE_IP_RANGE_CREATE, StorageNetworkIpRange.class.getName());
+        entityEventDetails.put(EVENT_STORAGE_IP_RANGE_DELETE, StorageNetworkIpRange.class.getName());
+        entityEventDetails.put(EVENT_STORAGE_IP_RANGE_UPDATE, StorageNetworkIpRange.class.getName());
+
+        // Configuration Table
+        entityEventDetails.put(EVENT_CONFIGURATION_VALUE_EDIT, Configuration.class.getName());
+
+        // Security Groups
+        entityEventDetails.put(EVENT_SECURITY_GROUP_AUTHORIZE_INGRESS, SecurityGroup.class.getName());
+        entityEventDetails.put(EVENT_SECURITY_GROUP_REVOKE_INGRESS, SecurityGroup.class.getName());
+        entityEventDetails.put(EVENT_SECURITY_GROUP_AUTHORIZE_EGRESS, SecurityGroup.class.getName());
+        entityEventDetails.put(EVENT_SECURITY_GROUP_REVOKE_EGRESS, SecurityGroup.class.getName());
+        entityEventDetails.put(EVENT_SECURITY_GROUP_CREATE, SecurityGroup.class.getName());
+        entityEventDetails.put(EVENT_SECURITY_GROUP_DELETE, SecurityGroup.class.getName());
+        entityEventDetails.put(EVENT_SECURITY_GROUP_ASSIGN, SecurityGroup.class.getName());
+        entityEventDetails.put(EVENT_SECURITY_GROUP_REMOVE, SecurityGroup.class.getName());
+
+        // Host
+        entityEventDetails.put(EVENT_HOST_RECONNECT,  Host.class.getName());
+
+        // Maintenance
+        entityEventDetails.put(EVENT_MAINTENANCE_CANCEL,  Host.class.getName());
+        entityEventDetails.put(EVENT_MAINTENANCE_CANCEL_PRIMARY_STORAGE,  Host.class.getName());
+        entityEventDetails.put(EVENT_MAINTENANCE_PREPARE,  Host.class.getName());
+        entityEventDetails.put(EVENT_MAINTENANCE_PREPARE_PRIMARY_STORAGE,  Host.class.getName());
+
+        // VPN
+        entityEventDetails.put(EVENT_REMOTE_ACCESS_VPN_CREATE, RemoteAccessVpn.class.getName());
+        entityEventDetails.put(EVENT_REMOTE_ACCESS_VPN_DESTROY, RemoteAccessVpn.class.getName());
+        entityEventDetails.put(EVENT_VPN_USER_ADD, RemoteAccessVpn.class.getName());
+        entityEventDetails.put(EVENT_VPN_USER_REMOVE, RemoteAccessVpn.class.getName());
+        entityEventDetails.put(EVENT_S2S_VPN_GATEWAY_CREATE, RemoteAccessVpn.class.getName());
+        entityEventDetails.put(EVENT_S2S_VPN_GATEWAY_DELETE, RemoteAccessVpn.class.getName());
+        entityEventDetails.put(EVENT_S2S_VPN_CUSTOMER_GATEWAY_CREATE, RemoteAccessVpn.class.getName());
+        entityEventDetails.put(EVENT_S2S_VPN_CUSTOMER_GATEWAY_DELETE, RemoteAccessVpn.class.getName());
+        entityEventDetails.put(EVENT_S2S_VPN_CUSTOMER_GATEWAY_UPDATE, RemoteAccessVpn.class.getName());
+        entityEventDetails.put(EVENT_S2S_VPN_CONNECTION_CREATE, RemoteAccessVpn.class.getName());
+        entityEventDetails.put(EVENT_S2S_VPN_CONNECTION_DELETE, RemoteAccessVpn.class.getName());
+        entityEventDetails.put(EVENT_S2S_VPN_CONNECTION_RESET, RemoteAccessVpn.class.getName());
+
+        // Custom certificates
+        entityEventDetails.put(EVENT_UPLOAD_CUSTOM_CERTIFICATE, "Certificate");
+
+        // OneToOnenat
+        entityEventDetails.put(EVENT_ENABLE_STATIC_NAT, StaticNat.class.getName());
+        entityEventDetails.put(EVENT_DISABLE_STATIC_NAT, StaticNat.class.getName());
+
+        entityEventDetails.put(EVENT_ZONE_VLAN_ASSIGN,Vlan.class.getName());
+        entityEventDetails.put(EVENT_ZONE_VLAN_RELEASE,Vlan.class.getName());
+
+        // Projects
+        entityEventDetails.put(EVENT_PROJECT_CREATE, Project.class.getName());
+        entityEventDetails.put(EVENT_PROJECT_UPDATE, Project.class.getName());
+        entityEventDetails.put(EVENT_PROJECT_DELETE, Project.class.getName());
+        entityEventDetails.put(EVENT_PROJECT_ACTIVATE, Project.class.getName());
+        entityEventDetails.put(EVENT_PROJECT_SUSPEND, Project.class.getName());
+        entityEventDetails.put(EVENT_PROJECT_ACCOUNT_ADD, Project.class.getName());
+        entityEventDetails.put(EVENT_PROJECT_INVITATION_UPDATE, Project.class.getName());
+        entityEventDetails.put(EVENT_PROJECT_INVITATION_REMOVE, Project.class.getName());
+        entityEventDetails.put(EVENT_PROJECT_ACCOUNT_REMOVE, Project.class.getName());
+
+        // Network as a Service
+        entityEventDetails.put(EVENT_NETWORK_ELEMENT_CONFIGURE,Network.class.getName());
+
+        // Physical Network Events
+        entityEventDetails.put(EVENT_PHYSICAL_NETWORK_CREATE, PhysicalNetwork.class.getName());
+        entityEventDetails.put(EVENT_PHYSICAL_NETWORK_DELETE, PhysicalNetwork.class.getName());
+        entityEventDetails.put(EVENT_PHYSICAL_NETWORK_UPDATE, PhysicalNetwork.class.getName());
+
+        // Physical Network Service Provider Events
+        entityEventDetails.put(EVENT_SERVICE_PROVIDER_CREATE, PhysicalNetworkServiceProvider.class.getName());
+        entityEventDetails.put(EVENT_SERVICE_PROVIDER_DELETE, PhysicalNetworkServiceProvider.class.getName());
+        entityEventDetails.put(EVENT_SERVICE_PROVIDER_UPDATE, PhysicalNetworkServiceProvider.class.getName());
+
+        // Physical Network TrafficType Events
+        entityEventDetails.put(EVENT_TRAFFIC_TYPE_CREATE, PhysicalNetworkTrafficType.class.getName());
+        entityEventDetails.put(EVENT_TRAFFIC_TYPE_DELETE, PhysicalNetworkTrafficType.class.getName());
+        entityEventDetails.put(EVENT_TRAFFIC_TYPE_UPDATE, PhysicalNetworkTrafficType.class.getName());
+
+        // external network device events
+        entityEventDetails.put(EVENT_EXTERNAL_LB_DEVICE_ADD, PhysicalNetwork.class.getName());
+        entityEventDetails.put(EVENT_EXTERNAL_LB_DEVICE_DELETE, PhysicalNetwork.class.getName());
+        entityEventDetails.put(EVENT_EXTERNAL_LB_DEVICE_CONFIGURE, PhysicalNetwork.class.getName());
+
+        // external switch management device events (E.g.: Cisco Nexus 1000v Virtual Supervisor Module.
+        entityEventDetails.put(EVENT_EXTERNAL_SWITCH_MGMT_DEVICE_ADD, "Nexus1000v");
+        entityEventDetails.put(EVENT_EXTERNAL_SWITCH_MGMT_DEVICE_DELETE, "Nexus1000v");
+        entityEventDetails.put(EVENT_EXTERNAL_SWITCH_MGMT_DEVICE_CONFIGURE, "Nexus1000v");
+        entityEventDetails.put(EVENT_EXTERNAL_SWITCH_MGMT_DEVICE_ENABLE, "Nexus1000v");
+        entityEventDetails.put(EVENT_EXTERNAL_SWITCH_MGMT_DEVICE_DISABLE, "Nexus1000v");
+
+
+        entityEventDetails.put(EVENT_EXTERNAL_FIREWALL_DEVICE_ADD, PhysicalNetwork.class.getName());
+        entityEventDetails.put(EVENT_EXTERNAL_FIREWALL_DEVICE_DELETE, PhysicalNetwork.class.getName());
+        entityEventDetails.put(EVENT_EXTERNAL_FIREWALL_DEVICE_CONFIGURE, PhysicalNetwork.class.getName());
+
+        // VPC
+        entityEventDetails.put(EVENT_VPC_CREATE, Vpc.class.getName());
+        entityEventDetails.put(EVENT_VPC_UPDATE, Vpc.class.getName());
+        entityEventDetails.put(EVENT_VPC_DELETE, Vpc.class.getName());
+        entityEventDetails.put(EVENT_VPC_RESTART, Vpc.class.getName());
+
+        // VPC offerings
+        entityEventDetails.put(EVENT_VPC_OFFERING_CREATE, Vpc.class.getName());
+        entityEventDetails.put(EVENT_VPC_OFFERING_UPDATE, Vpc.class.getName());
+        entityEventDetails.put(EVENT_VPC_OFFERING_DELETE, Vpc.class.getName());
+
+        // Private gateway
+        entityEventDetails.put(EVENT_PRIVATE_GATEWAY_CREATE, PrivateGateway.class.getName());
+        entityEventDetails.put(EVENT_PRIVATE_GATEWAY_DELETE, PrivateGateway.class.getName());
+
+        // Static routes
+        entityEventDetails.put(EVENT_STATIC_ROUTE_CREATE, StaticRoute.class.getName());
+        entityEventDetails.put(EVENT_STATIC_ROUTE_DELETE, StaticRoute.class.getName());
+
+        // tag related events
+        entityEventDetails.put(EVENT_TAGS_CREATE, "Tag");
+        entityEventDetails.put(EVENT_TAGS_DELETE, "tag");
+
+        // external network device events
+        entityEventDetails.put(EVENT_EXTERNAL_NVP_CONTROLLER_ADD,  "NvpController");
+        entityEventDetails.put(EVENT_EXTERNAL_NVP_CONTROLLER_DELETE,  "NvpController");
+        entityEventDetails.put(EVENT_EXTERNAL_NVP_CONTROLLER_CONFIGURE, "NvpController");
+
+        // AutoScale
+        entityEventDetails.put(EVENT_COUNTER_CREATE, AutoScaleCounter.class.getName());
+        entityEventDetails.put(EVENT_COUNTER_DELETE, AutoScaleCounter.class.getName());
+        entityEventDetails.put(EVENT_CONDITION_CREATE, Condition.class.getName());
+        entityEventDetails.put(EVENT_CONDITION_DELETE, Condition.class.getName());
+        entityEventDetails.put(EVENT_AUTOSCALEPOLICY_CREATE, AutoScalePolicy.class.getName());
+        entityEventDetails.put(EVENT_AUTOSCALEPOLICY_UPDATE, AutoScalePolicy.class.getName());
+        entityEventDetails.put(EVENT_AUTOSCALEPOLICY_DELETE, AutoScalePolicy.class.getName());
+        entityEventDetails.put(EVENT_AUTOSCALEVMPROFILE_CREATE, AutoScaleVmProfile.class.getName());
+        entityEventDetails.put(EVENT_AUTOSCALEVMPROFILE_DELETE, AutoScaleVmProfile.class.getName());
+        entityEventDetails.put(EVENT_AUTOSCALEVMPROFILE_UPDATE, AutoScaleVmProfile.class.getName());
+        entityEventDetails.put(EVENT_AUTOSCALEVMGROUP_CREATE, AutoScaleVmGroup.class.getName());
+        entityEventDetails.put(EVENT_AUTOSCALEVMGROUP_DELETE, AutoScaleVmGroup.class.getName());
+        entityEventDetails.put(EVENT_AUTOSCALEVMGROUP_UPDATE, AutoScaleVmGroup.class.getName());
+        entityEventDetails.put(EVENT_AUTOSCALEVMGROUP_ENABLE, AutoScaleVmGroup.class.getName());
+        entityEventDetails.put(EVENT_AUTOSCALEVMGROUP_DISABLE, AutoScaleVmGroup.class.getName());
+    }
+
+    public static String getEntityForEvent (String eventName) {
+        String entityClassName = entityEventDetails.get(eventName);
+        if (entityClassName == null || entityClassName.isEmpty()) {
+            return null;
+        }
+        int index = entityClassName.lastIndexOf(".");
+        String entityName = entityClassName;
+        if (index != -1) {
+            entityName = entityClassName.substring(index+1);
+        }
+        return entityName;
+    }
 }
diff --git a/api/src/com/cloud/network/Network.java b/api/src/com/cloud/network/Network.java
index 413b6d9..1dbb327 100644
--- a/api/src/com/cloud/network/Network.java
+++ b/api/src/com/cloud/network/Network.java
@@ -16,26 +16,25 @@
 // under the License.
 package com.cloud.network;
 
-import org.apache.cloudstack.acl.ControlledEntity;
 import com.cloud.network.Networks.BroadcastDomainType;
 import com.cloud.network.Networks.Mode;
 import com.cloud.network.Networks.TrafficType;
-import com.cloud.utils.fsm.FiniteState;
-import com.cloud.utils.fsm.StateMachine;
+import com.cloud.utils.fsm.StateMachine2;
+import com.cloud.utils.fsm.StateObject;
+import org.apache.cloudstack.acl.ControlledEntity;
 import org.apache.cloudstack.api.Identity;
 import org.apache.cloudstack.api.InternalIdentity;
 
 import java.net.URI;
 import java.util.ArrayList;
 import java.util.List;
-import java.util.Set;
 
 /**
  * owned by an account.
  */
-public interface Network extends ControlledEntity, InternalIdentity, Identity {
+public interface Network extends ControlledEntity, StateObject<Network.State>, InternalIdentity, Identity {
 
-    public enum GuestType {
+  public enum GuestType {
         Shared,
         Isolated
     }
@@ -204,7 +203,8 @@
         OperationFailed;
     }
 
-    enum State implements FiniteState<State, Event> {
+    public enum State {
+
         Allocated("Indicates the network configuration is in allocated but not setup"),
         Setup("Indicates the network configuration is setup"),
         Implementing("Indicates the network configuration is being implemented"),
@@ -212,39 +212,8 @@
         Shutdown("Indicates the network configuration is being destroyed"),
         Destroy("Indicates that the network is destroyed");
 
+        protected static final StateMachine2<State, Network.Event, Network> s_fsm = new StateMachine2<State, Network.Event, Network>();
 
-        @Override
-        public StateMachine<State, Event> getStateMachine() {
-            return s_fsm;
-        }
-
-        @Override
-        public State getNextState(Event event) {
-            return s_fsm.getNextState(this, event);
-        }
-
-        @Override
-        public List<State> getFromStates(Event event) {
-            return s_fsm.getFromStates(this, event);
-        }
-
-        @Override
-        public Set<Event> getPossibleEvents() {
-            return s_fsm.getPossibleEvents(this);
-        }
-
-        String _description;
-
-        @Override
-        public String getDescription() {
-            return _description;
-        }
-
-        private State(String description) {
-            _description = description;
-        }
-
-        private static StateMachine<State, Event> s_fsm = new StateMachine<State, Event>();
         static {
             s_fsm.addTransition(State.Allocated, Event.ImplementNetwork, State.Implementing);
             s_fsm.addTransition(State.Implementing, Event.OperationSucceeded, State.Implemented);
@@ -253,6 +222,15 @@
             s_fsm.addTransition(State.Shutdown, Event.OperationSucceeded, State.Allocated);
             s_fsm.addTransition(State.Shutdown, Event.OperationFailed, State.Implemented);
         }
+
+        public static StateMachine2<State, Network.Event, Network> getStateMachine() {
+            return s_fsm;
+        }
+
+        String _description;
+        private State(String description) {
+            _description = description;
+        }
     }
 
     String getName();
diff --git a/api/src/com/cloud/storage/Snapshot.java b/api/src/com/cloud/storage/Snapshot.java
index 99bdee6..2e2965a 100644
--- a/api/src/com/cloud/storage/Snapshot.java
+++ b/api/src/com/cloud/storage/Snapshot.java
@@ -16,14 +16,16 @@
 // under the License.
 package com.cloud.storage;
 
-import java.util.Date;
-
-import org.apache.cloudstack.acl.ControlledEntity;
 import com.cloud.hypervisor.Hypervisor.HypervisorType;
+import com.cloud.utils.fsm.StateMachine2;
+import com.cloud.utils.fsm.StateObject;
+import org.apache.cloudstack.acl.ControlledEntity;
 import org.apache.cloudstack.api.Identity;
 import org.apache.cloudstack.api.InternalIdentity;
 
-public interface Snapshot extends ControlledEntity, Identity, InternalIdentity {
+import java.util.Date;
+
+public interface Snapshot extends ControlledEntity, Identity, InternalIdentity, StateObject<Snapshot.State> {
     public enum Type {
         MANUAL,
         RECURRING,
@@ -51,13 +53,29 @@
         }
     }
 
-    public enum Status {
+    public enum State {
         Creating,
         CreatedOnPrimary,
         BackingUp,
         BackedUp,
         Error;
 
+        private final static StateMachine2<State, Event, Snapshot> s_fsm = new StateMachine2<State, Event, Snapshot>();
+
+        public static StateMachine2<State, Event, Snapshot> getStateMachine() {
+            return s_fsm;
+        }
+
+        static {
+            s_fsm.addTransition(null, Event.CreateRequested, Creating);
+            s_fsm.addTransition(Creating, Event.OperationSucceeded, CreatedOnPrimary);
+            s_fsm.addTransition(Creating, Event.OperationNotPerformed, BackedUp);
+            s_fsm.addTransition(Creating, Event.OperationFailed, Error);
+            s_fsm.addTransition(CreatedOnPrimary, Event.BackupToSecondary, BackingUp);
+            s_fsm.addTransition(BackingUp, Event.OperationSucceeded, BackedUp);
+            s_fsm.addTransition(BackingUp, Event.OperationFailed, Error);
+        }
+
         public String toString() {
             return this.name();
         }
@@ -67,6 +85,15 @@
         }
     }
 
+    enum Event {
+        CreateRequested,
+        OperationNotPerformed,
+        BackupToSecondary,
+        BackedupToSecondary,
+        OperationSucceeded,
+        OperationFailed
+    }
+
     public static final long MANUAL_POLICY_ID = 0L;
 
     long getAccountId();
@@ -81,7 +108,7 @@
 
     Type getType();
 
-    Status getStatus();
+    State getState();
 
     HypervisorType getHypervisorType();
 
diff --git a/api/src/org/apache/cloudstack/api/response/SnapshotResponse.java b/api/src/org/apache/cloudstack/api/response/SnapshotResponse.java
index 8ea0d7f..58b7cf1 100644
--- a/api/src/org/apache/cloudstack/api/response/SnapshotResponse.java
+++ b/api/src/org/apache/cloudstack/api/response/SnapshotResponse.java
@@ -16,16 +16,16 @@
 // under the License.
 package org.apache.cloudstack.api.response;
 
-import java.util.Date;
-import java.util.List;
-
-import org.apache.cloudstack.api.ApiConstants;
 import com.cloud.serializer.Param;
 import com.cloud.storage.Snapshot;
 import com.google.gson.annotations.SerializedName;
+import org.apache.cloudstack.api.ApiConstants;
 import org.apache.cloudstack.api.BaseResponse;
 import org.apache.cloudstack.api.EntityReference;
 
+import java.util.Date;
+import java.util.List;
+
 @EntityReference(value=Snapshot.class)
 @SuppressWarnings("unused")
 public class SnapshotResponse extends BaseResponse implements ControlledEntityResponse {
@@ -81,7 +81,7 @@
 
     @SerializedName(ApiConstants.STATE)
     @Param(description = "the state of the snapshot. BackedUp means that snapshot is ready to be used; Creating - the snapshot is being allocated on the primary storage; BackingUp - the snapshot is being backed up on secondary storage")
-    private Snapshot.Status state;
+    private Snapshot.State state;
 
     @SerializedName(ApiConstants.TAGS)  @Param(description="the list of resource tags associated with snapshot", responseObject = ResourceTagResponse.class)
     private List<ResourceTagResponse> tags;
@@ -149,7 +149,7 @@
         this.intervalType = intervalType;
     }
 
-    public void setState(Snapshot.Status state) {
+    public void setState(Snapshot.State state) {
         this.state = state;
     }
 
diff --git a/client/pom.xml b/client/pom.xml
index 7ebe50c..63ec2ef 100644
--- a/client/pom.xml
+++ b/client/pom.xml
@@ -117,6 +117,11 @@
       <version>${project.version}</version>
     </dependency>
     <dependency>
+      <groupId>org.apache.cloudstack</groupId>
+      <artifactId>cloud-mom-rabbitmq</artifactId>
+      <version>${project.version}</version>
+    </dependency>
+    <dependency>
       <groupId>mysql</groupId>
       <artifactId>mysql-connector-java</artifactId>
       <version>${cs.mysql.version}</version>
diff --git a/core/src/com/cloud/storage/SnapshotVO.java b/core/src/com/cloud/storage/SnapshotVO.java
index e5e3650..c1c5f21 100644
--- a/core/src/com/cloud/storage/SnapshotVO.java
+++ b/core/src/com/cloud/storage/SnapshotVO.java
@@ -16,23 +16,13 @@
 // under the License.
 package com.cloud.storage;
 
-import java.util.Date;
-import java.util.UUID;
-
-import javax.persistence.Column;
-import javax.persistence.Entity;
-import javax.persistence.EnumType;
-import javax.persistence.Enumerated;
-import javax.persistence.GeneratedValue;
-import javax.persistence.GenerationType;
-import javax.persistence.Id;
-import javax.persistence.Table;
-
-import org.apache.cloudstack.api.Identity;
 import com.cloud.hypervisor.Hypervisor.HypervisorType;
 import com.cloud.utils.db.GenericDao;
 import com.google.gson.annotations.Expose;
-import org.apache.cloudstack.api.InternalIdentity;
+
+import javax.persistence.*;
+import java.util.Date;
+import java.util.UUID;
 
 @Entity
 @Table(name="snapshots")
@@ -69,7 +59,7 @@
     @Expose
     @Column(name="status", updatable = true, nullable=false)
     @Enumerated(value=EnumType.STRING)
-    private Status status;
+    private State status;
 
     @Column(name="snapshot_type")
     short snapshotType;
@@ -127,7 +117,7 @@
         this.snapshotType = snapshotType;
         this.typeDescription = typeDescription;
         this.size = size;
-        this.status = Status.Creating;
+        this.status = State.Creating;
         this.prevSnapshotId = 0;
         this.hypervisorType = hypervisorType;
         this.version = "2.2";
@@ -252,11 +242,11 @@
     }
 
 	@Override
-    public Status getStatus() {
+    public State getState() {
 		return status;
 	}
 
-	public void setStatus(Status status) {
+	public void setStatus(State status) {
 		this.status = status;
 	}
 
diff --git a/framework/events/pom.xml b/framework/events/pom.xml
new file mode 100644
index 0000000..ef812e5
--- /dev/null
+++ b/framework/events/pom.xml
@@ -0,0 +1,47 @@
+<!--
+  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.
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+  <modelVersion>4.0.0</modelVersion>
+  <artifactId>cloud-framework-events</artifactId>
+  <name>Apache CloudStack Event Notification Framework</name>
+  <parent>
+    <groupId>org.apache.cloudstack</groupId>
+    <artifactId>cloudstack-framework</artifactId>
+    <version>4.1.0-SNAPSHOT</version>
+    <relativePath>../pom.xml</relativePath>
+  </parent>
+  <dependencies>
+    <dependency>
+      <groupId>org.apache.cloudstack</groupId>
+        <artifactId>cloud-utils</artifactId>
+        <version>${project.version}</version>
+     </dependency>
+    <dependency>
+        <groupId>com.google.code.gson</groupId>
+        <artifactId>gson</artifactId>
+        <version>${cs.gson.version}</version>
+    </dependency>
+  </dependencies>
+  <build>
+    <defaultGoal>install</defaultGoal>
+    <sourceDirectory>src</sourceDirectory>
+    <testSourceDirectory>test</testSourceDirectory>
+  </build>
+</project>
diff --git a/framework/events/src/org/apache/cloudstack/framework/events/Event.java b/framework/events/src/org/apache/cloudstack/framework/events/Event.java
new file mode 100644
index 0000000..eb6f48d
--- /dev/null
+++ b/framework/events/src/org/apache/cloudstack/framework/events/Event.java
@@ -0,0 +1,94 @@
+/*
+ * 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.
+ */
+
+package org.apache.cloudstack.framework.events;
+
+import com.google.gson.Gson;
+
+public class Event {
+
+    String eventCategory;
+    String eventType;
+    String eventSource;
+    String resourceType;
+    String resourceUUID;
+    String description;
+
+    public Event(String eventSource, String eventCategory, String eventType, String resourceType,
+                 String resourceUUID) {
+        this.eventCategory = eventCategory;
+        this.eventType = eventType;
+        this.eventSource = eventSource;
+        this.resourceType = resourceType;
+        this.resourceUUID = resourceUUID;
+    }
+
+    public String getEventCategory() {
+        return eventCategory;
+    }
+
+    public void setEventCategory(String category) {
+        eventCategory = category;
+    }
+
+    public String getEventType() {
+        return eventType;
+    }
+
+    public void setEventType(String type) {
+        eventType = type;
+    }
+
+    public String getEventSource() {
+        return eventSource;
+    }
+
+    void setEventSource(String source) {
+        eventSource = source;
+    }
+
+    public String getDescription() {
+        return description;
+    }
+
+    public void setDescription (Object message) {
+        Gson gson = new Gson();
+        this.description = gson.toJson(message).toString();
+    }
+
+    public void setDescription(String description) {
+        this.description = description;
+    }
+
+    public String getResourceType() {
+        return resourceType;
+    }
+
+    public void setResourceType(String resourceType) {
+        this.resourceType = resourceType;
+    }
+
+    public void setResourceUUID(String uuid) {
+        this.resourceUUID = uuid;
+    }
+
+    public String getResourceUUID () {
+        return resourceUUID;
+    }
+}
\ No newline at end of file
diff --git a/framework/events/src/org/apache/cloudstack/framework/events/EventBus.java b/framework/events/src/org/apache/cloudstack/framework/events/EventBus.java
new file mode 100644
index 0000000..c16ee6f
--- /dev/null
+++ b/framework/events/src/org/apache/cloudstack/framework/events/EventBus.java
@@ -0,0 +1,55 @@
+/*
+ * 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.
+ */
+
+package org.apache.cloudstack.framework.events;
+
+import com.cloud.utils.component.Adapter;
+
+import java.util.UUID;
+
+/**
+ * Interface to publish and subscribe to CloudStack events
+ *
+ */
+public interface EventBus extends Adapter{
+
+    /**
+     * publish an event on to the event bus
+     *
+     * @param event event that needs to be published on the event bus
+     */
+    void publish(Event event) throws EventBusException;
+
+    /**
+     * subscribe to events that matches specified event topics
+     *
+     * @param topic defines category and type of the events being subscribed to
+     * @param subscriber subscriber that intends to receive event notification
+     * @return UUID returns the subscription ID
+     */
+     UUID subscribe(EventTopic topic, EventSubscriber subscriber) throws EventBusException;
+
+    /**
+     * unsubscribe to events of a category and a type
+     *
+     * @param subscriber subscriber that intends to unsubscribe from the event notification
+     */
+    void unsubscribe(UUID subscriberId, EventSubscriber subscriber) throws EventBusException;
+
+}
diff --git a/framework/events/src/org/apache/cloudstack/framework/events/EventBusException.java b/framework/events/src/org/apache/cloudstack/framework/events/EventBusException.java
new file mode 100644
index 0000000..5654ba0
--- /dev/null
+++ b/framework/events/src/org/apache/cloudstack/framework/events/EventBusException.java
@@ -0,0 +1,26 @@
+/*
+ * 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.
+ */
+
+package org.apache.cloudstack.framework.events;
+
+public class EventBusException extends Exception{
+    public EventBusException (String msg) {
+      super(msg);
+    }
+}
diff --git a/framework/events/src/org/apache/cloudstack/framework/events/EventSubscriber.java b/framework/events/src/org/apache/cloudstack/framework/events/EventSubscriber.java
new file mode 100644
index 0000000..b1c30c2
--- /dev/null
+++ b/framework/events/src/org/apache/cloudstack/framework/events/EventSubscriber.java
@@ -0,0 +1,30 @@
+/*
+ * 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/LICENSE2.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.
+ */
+
+package org.apache.cloudstack.framework.events;
+
+public interface EventSubscriber {
+
+    /**
+     * Callback method. EventBus calls this method on occurrence of subscribed event
+     *
+     * @param event details of the event
+     */
+    void onEvent(Event event);
+}
diff --git a/framework/events/src/org/apache/cloudstack/framework/events/EventTopic.java b/framework/events/src/org/apache/cloudstack/framework/events/EventTopic.java
new file mode 100644
index 0000000..19b727d
--- /dev/null
+++ b/framework/events/src/org/apache/cloudstack/framework/events/EventTopic.java
@@ -0,0 +1,57 @@
+/*
+ * 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.
+ */
+
+package org.apache.cloudstack.framework.events;
+
+public class EventTopic {
+
+    String eventCategory;
+    String eventType;
+    String resourceType;
+    String resourceUUID;
+    String eventSource;
+
+    public EventTopic(String eventCategory, String eventType, String resourceType, String resourceUUID, String eventSource) {
+        this.eventCategory = eventCategory;
+        this.eventType = eventType;
+        this.resourceType = resourceType;
+        this.resourceUUID = resourceUUID;
+        this.eventSource = eventSource;
+    }
+
+    public String getEventCategory() {
+        return eventCategory;
+    }
+
+    public String getEventType() {
+        return eventType;
+    }
+
+    public String getResourceType() {
+        return resourceType;
+    }
+
+    public String getEventSource() {
+        return eventSource;
+    }
+
+    public String getResourceUUID() {
+        return resourceUUID;
+    }
+}
diff --git a/framework/pom.xml b/framework/pom.xml
new file mode 100644
index 0000000..81e0916
--- /dev/null
+++ b/framework/pom.xml
@@ -0,0 +1,35 @@
+<!--
+  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.
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+  <modelVersion>4.0.0</modelVersion>
+  <artifactId>cloudstack-framework</artifactId>
+  <name>Apache CloudStack framework POM</name>
+  <packaging>pom</packaging>
+  <parent>
+    <groupId>org.apache.cloudstack</groupId>
+    <artifactId>cloudstack</artifactId>
+    <version>4.1.0-SNAPSHOT</version>
+  </parent>
+  <build>
+    <defaultGoal>install</defaultGoal>
+  </build>
+  <modules>
+    <module>events</module>
+  </modules>
+</project>
diff --git a/plugins/event-bus/rabbitmq/pom.xml b/plugins/event-bus/rabbitmq/pom.xml
new file mode 100644
index 0000000..6a47983
--- /dev/null
+++ b/plugins/event-bus/rabbitmq/pom.xml
@@ -0,0 +1,46 @@
+<!--
+  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.
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+  <modelVersion>4.0.0</modelVersion>
+  <artifactId>cloud-mom-rabbitmq</artifactId>
+  <name>Apache CloudStack Plugin - RabbitMQ Event Bus</name>
+  <parent>
+    <groupId>org.apache.cloudstack</groupId>
+    <artifactId>cloudstack-plugins</artifactId>
+    <version>4.1.0-SNAPSHOT</version>
+    <relativePath>../../pom.xml</relativePath>
+  </parent>
+  <dependencies>
+    <dependency>
+    <groupId>com.rabbitmq</groupId>
+      <artifactId>amqp-client</artifactId>
+        <version>2.8.7</version>
+    </dependency>
+    <dependency>
+    <groupId>org.apache.cloudstack</groupId>
+      <artifactId>cloud-framework-events</artifactId>
+      <version>${project.version}</version>
+    </dependency>
+  </dependencies>
+  <build>
+    <defaultGoal>install</defaultGoal>
+    <sourceDirectory>src</sourceDirectory>
+  </build>
+</project>
diff --git a/plugins/event-bus/rabbitmq/src/org/apache/cloudstack/mom/rabbitmq/RabbitMQEventBus.java b/plugins/event-bus/rabbitmq/src/org/apache/cloudstack/mom/rabbitmq/RabbitMQEventBus.java
new file mode 100644
index 0000000..3a06c42
--- /dev/null
+++ b/plugins/event-bus/rabbitmq/src/org/apache/cloudstack/mom/rabbitmq/RabbitMQEventBus.java
@@ -0,0 +1,555 @@
+/*
+ * 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.
+ */
+
+package org.apache.cloudstack.mom.rabbitmq;
+
+import com.rabbitmq.client.*;
+import org.apache.cloudstack.framework.events.*;
+import org.apache.log4j.Logger;
+
+import com.cloud.utils.Ternary;
+
+import javax.ejb.Local;
+import javax.naming.ConfigurationException;
+import java.io.IOException;
+import java.net.ConnectException;
+import java.util.Map;
+import java.util.UUID;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+
+@Local(value=EventBus.class)
+public class RabbitMQEventBus implements EventBus {
+
+    // details of AMQP server
+    private static String _amqpHost;
+    private static Integer _port;
+    private static String _username;
+    private static String _password;
+
+    // AMQP exchange name where all CloudStack events will be published
+    private static String _amqpExchangeName;
+
+    // hashmap to book keep the registered subscribers
+    private static ConcurrentHashMap<String, Ternary<String, Channel, EventSubscriber>> _subscribers;
+
+    // connection to AMQP server,
+    private static Connection _connection=null;
+
+    // AMQP server should consider messages acknowledged once delivered if _autoAck is true
+    private static boolean _autoAck = true;
+
+    private ExecutorService executorService;
+    private String _name;
+    private static DisconnectHandler disconnectHandler;
+    private static Integer _retryInterval;
+    private static final Logger s_logger = Logger.getLogger(RabbitMQEventBus.class);
+
+    @Override
+    public boolean configure(String name, Map<String, Object> params) throws ConfigurationException {
+
+        _amqpHost = (String) params.get("server");
+        if (_amqpHost == null || _amqpHost.isEmpty()) {
+            throw new ConfigurationException("Unable to get the AMQP server details");
+        }
+
+        _username = (String) params.get("username");
+        if (_username == null || _username.isEmpty()) {
+            throw new ConfigurationException("Unable to get the username details");
+        }
+
+        _password = (String) params.get("password");
+        if (_password == null || _password.isEmpty()) {
+            throw new ConfigurationException("Unable to get the password details");
+        }
+
+        _amqpExchangeName = (String) params.get("exchangename");
+        if (_amqpExchangeName == null || _amqpExchangeName.isEmpty()) {
+            throw new ConfigurationException("Unable to get the _exchange details on the AMQP server");
+        }
+
+        try {
+            String portStr =  (String) params.get("port");
+            if (portStr == null || portStr.isEmpty()) {
+                throw new ConfigurationException("Unable to get the port details of AMQP server");
+            }
+            _port = Integer.parseInt(portStr);
+
+            String retryIntervalStr = (String) params.get("retryinterval");
+            if (retryIntervalStr == null || retryIntervalStr.isEmpty()) {
+                // default to 10s to try out reconnect
+                retryIntervalStr = "10000";
+            }
+            _retryInterval = Integer.parseInt(retryIntervalStr);
+        } catch (NumberFormatException e) {
+            throw new ConfigurationException("Invalid port number/retry interval");
+        }
+
+        _subscribers = new ConcurrentHashMap<String, Ternary<String, Channel, EventSubscriber>>();
+
+        executorService = Executors.newCachedThreadPool();
+        disconnectHandler = new DisconnectHandler();
+        _name = name;
+        return true;
+    }
+
+    /** Call to subscribe to interested set of events
+     *
+     * @param topic defines category and type of the events being subscribed to
+     * @param subscriber subscriber that intends to receive event notification
+     * @return UUID that represents the subscription with event bus
+     * @throws EventBusException
+     */
+    @Override
+    public UUID subscribe(EventTopic topic, EventSubscriber subscriber) throws EventBusException {
+
+        if (subscriber == null || topic == null) {
+            throw new EventBusException("Invalid EventSubscriber/EventTopic object passed.");
+        }
+
+        // create a UUID, that will be used for managing subscriptions and also used as queue name
+        // for on the queue used for the subscriber on the AMQP broker
+        UUID queueId = UUID.randomUUID();
+        String queueName = queueId.toString();
+
+        try {
+            String bindingKey = createBindingKey(topic);
+
+            // store the subscriber details before creating channel
+            _subscribers.put(queueName, new Ternary(bindingKey, null, subscriber));
+
+            // create a channel dedicated for this subscription
+            Connection connection = getConnection();
+            Channel channel = createChannel(connection);
+
+            // create a queue and bind it to the exchange with binding key formed from event topic
+            createExchange(channel, _amqpExchangeName);
+            channel.queueDeclare(queueName, false, false, false, null);
+            channel.queueBind(queueName, _amqpExchangeName, bindingKey);
+
+            // register a callback handler to receive the events that a subscriber subscribed to
+            channel.basicConsume(queueName, _autoAck, queueName,
+                    new DefaultConsumer(channel) {
+                        @Override
+                        public void handleDelivery(String queueName,
+                                                   Envelope envelope,
+                                                   AMQP.BasicProperties properties,
+                                                   byte[] body)
+                            throws IOException {
+                            Ternary<String, Channel, EventSubscriber> queueDetails = _subscribers.get(queueName);
+                            if (queueDetails != null) {
+                                EventSubscriber subscriber = queueDetails.third();
+                                String routingKey =  envelope.getRoutingKey();
+                                String eventSource = getEventSourceFromRoutingKey(routingKey);
+                                String eventCategory = getEventCategoryFromRoutingKey(routingKey);
+                                String eventType = getEventTypeFromRoutingKey(routingKey);
+                                String resourceType = getResourceTypeFromRoutingKey(routingKey);
+                                String resourceUUID = getResourceUUIDFromRoutingKey(routingKey);
+                                Event event = new Event(eventSource, eventCategory, eventType,
+                                        resourceType, resourceUUID);
+                                event.setDescription(new String(body));
+
+                                // deliver the event to call back object provided by subscriber
+                                subscriber.onEvent(event);
+                            }
+                        }
+                    }
+            );
+
+            // update the channel details for the subscription
+            Ternary<String, Channel, EventSubscriber> queueDetails = _subscribers.get(queueName);
+            queueDetails.second(channel);
+            _subscribers.put(queueName, queueDetails);
+
+        } catch (AlreadyClosedException closedException) {
+            s_logger.warn("Connection to AMQP service is lost. Subscription:" + queueName +
+                    " will be active after reconnection");
+        } catch (ConnectException connectException) {
+            s_logger.warn("Connection to AMQP service is lost. Subscription:" + queueName +
+                    " will be active after reconnection");
+        } catch (Exception e) {
+            throw new EventBusException("Failed to subscribe to event due to " + e.getMessage());
+        }
+
+        return queueId;
+    }
+
+    @Override
+    public void unsubscribe(UUID subscriberId, EventSubscriber subscriber) throws EventBusException {
+        try {
+            String classname =  subscriber.getClass().getName();
+            String queueName = UUID.nameUUIDFromBytes(classname.getBytes()).toString();
+            Ternary<String, Channel, EventSubscriber> queueDetails = _subscribers.get(queueName);
+            Channel channel = queueDetails.second();
+            channel.basicCancel(queueName);
+            _subscribers.remove(queueName, queueDetails);
+        } catch (Exception e) {
+            throw new EventBusException("Failed to unsubscribe from event bus due to " + e.getMessage());
+        }
+    }
+
+    // publish event on to the exchange created on AMQP server
+    @Override
+    public void publish(Event event) throws EventBusException {
+
+        String routingKey = createRoutingKey(event);
+        String eventDescription = event.getDescription();
+
+        try {
+            Connection connection = getConnection();
+            Channel channel = createChannel(connection);
+            createExchange(channel, _amqpExchangeName);
+            publishEventToExchange(channel, _amqpExchangeName, routingKey, eventDescription);
+            channel.close();
+        } catch (AlreadyClosedException e) {
+            closeConnection();
+            throw new EventBusException("Failed to publish event to message broker as connection to AMQP broker in lost");
+        } catch (Exception e) {
+            throw new EventBusException("Failed to publish event to message broker due to " + e.getMessage());
+        }
+    }
+
+    /** creates a routing key from the event details.
+     *  created routing key will be used while publishing the message to exchange on AMQP server
+     */
+    private String createRoutingKey(Event event) {
+
+        StringBuilder routingKey = new StringBuilder();
+
+        String eventSource =  replaceNullWithWildcard(event.getEventSource());
+        eventSource = eventSource.replace(".", "-");
+
+        String eventCategory = replaceNullWithWildcard(event.getEventCategory());
+        eventCategory = eventCategory.replace(".", "-");
+
+        String eventType = replaceNullWithWildcard(event.getEventType());
+        eventType = eventType.replace(".", "-");
+
+        String resourceType = replaceNullWithWildcard(event.getResourceType());
+        resourceType = resourceType.replace(".", "-");
+
+        String resourceUuid = replaceNullWithWildcard(event.getResourceUUID());
+        resourceUuid = resourceUuid.replace(".", "-");
+
+        // routing key will be of format: eventSource.eventCategory.eventType.resourceType.resourceUuid
+        routingKey.append(eventSource);
+        routingKey.append(".");
+        routingKey.append(eventCategory);
+        routingKey.append(".");
+        routingKey.append(eventType);
+        routingKey.append(".");
+        routingKey.append(resourceType);
+        routingKey.append(".");
+        routingKey.append(resourceUuid);
+
+        return routingKey.toString();
+    }
+
+    /** creates a binding key from the event topic that subscriber specified
+     *  binding key will be used to bind the queue created for subscriber to exchange on AMQP server
+     */
+    private String createBindingKey(EventTopic topic) {
+
+        StringBuilder bindingKey = new StringBuilder();
+
+        String eventSource =  replaceNullWithWildcard(topic.getEventSource());
+        eventSource = eventSource.replace(".", "-");
+
+        String eventCategory = replaceNullWithWildcard(topic.getEventCategory());
+        eventCategory = eventCategory.replace(".", "-");
+
+        String eventType = replaceNullWithWildcard(topic.getEventType());
+        eventType = eventType.replace(".", "-");
+
+        String resourceType = replaceNullWithWildcard(topic.getResourceType());
+        resourceType = resourceType.replace(".", "-");
+
+        String resourceUuid = replaceNullWithWildcard(topic.getResourceUUID());
+        resourceUuid = resourceUuid.replace(".", "-");
+
+        // binding key will be of format: eventSource.eventCategory.eventType.resourceType.resourceUuid
+        bindingKey.append(eventSource);
+        bindingKey.append(".");
+        bindingKey.append(eventCategory);
+        bindingKey.append(".");
+        bindingKey.append(eventType);
+        bindingKey.append(".");
+        bindingKey.append(resourceType);
+        bindingKey.append(".");
+        bindingKey.append(resourceUuid);
+
+        return bindingKey.toString();
+    }
+
+    private synchronized Connection getConnection() throws Exception {
+        if (_connection == null) {
+            try {
+                return createConnection();
+            } catch (Exception e) {
+                s_logger.error("Failed to create a connection to AMQP server due to " + e.getMessage());
+                throw e;
+            }
+        } else {
+            return _connection;
+        }
+    }
+
+    private synchronized Connection createConnection() throws Exception {
+        try {
+            ConnectionFactory factory = new ConnectionFactory();
+            factory.setUsername(_username);
+            factory.setPassword(_password);
+            factory.setVirtualHost("/");
+            factory.setHost(_amqpHost);
+            factory.setPort(_port);
+            Connection connection = factory.newConnection();
+            connection.addShutdownListener(disconnectHandler);
+            _connection = connection;
+            return _connection;
+        } catch (Exception e) {
+            throw e;
+        }
+    }
+
+    private synchronized void closeConnection() {
+        try {
+            if (_connection != null) {
+                _connection.close();
+            }
+        } catch (Exception e) {
+            s_logger.warn("Failed to close connection to AMQP server due to " + e.getMessage());
+        }
+        _connection = null;
+    }
+
+    private synchronized void abortConnection () {
+        if (_connection == null)
+            return;
+
+        try {
+            _connection.abort();
+        } catch (Exception e) {
+            s_logger.warn("Failed to abort connection due to " + e.getMessage());
+        }
+        _connection = null;
+    }
+
+    private String replaceNullWithWildcard(String key) {
+        if (key == null || key.isEmpty()) {
+            return "*";
+        } else {
+            return key;
+        }
+    }
+
+    private Channel createChannel(Connection connection) throws Exception {
+        try {
+            return connection.createChannel();
+        } catch (java.io.IOException exception) {
+            s_logger.warn("Failed to create a channel due to " + exception.getMessage());
+            throw exception;
+        }
+    }
+
+    private void createExchange(Channel channel, String exchangeName) throws Exception {
+        try {
+            channel.exchangeDeclare(exchangeName, "topic", true);
+        } catch (java.io.IOException exception) {
+            s_logger.error("Failed to create exchange" + exchangeName + " on RabbitMQ server");
+            throw exception;
+        }
+    }
+
+    private void publishEventToExchange(Channel channel, String exchangeName,
+                                        String routingKey, String eventDescription) throws Exception {
+        try {
+            byte[] messageBodyBytes = eventDescription.getBytes();
+            channel.basicPublish(exchangeName, routingKey, MessageProperties.PERSISTENT_TEXT_PLAIN, messageBodyBytes);
+        } catch (Exception e) {
+            s_logger.error("Failed to publish event " + routingKey + " on exchange " + exchangeName +
+                    "  of message broker due to " + e.getMessage());
+            throw e;
+        }
+    }
+
+    private String getEventCategoryFromRoutingKey(String routingKey) {
+        String[] keyParts =  routingKey.split("\\.");
+        return keyParts[1];
+    }
+
+    private String getEventTypeFromRoutingKey(String routingKey) {
+        String[] keyParts =  routingKey.split("\\.");
+        return keyParts[2];
+    }
+
+    private String getEventSourceFromRoutingKey(String routingKey) {
+        String[] keyParts =  routingKey.split("\\.");
+        return keyParts[0];
+    }
+
+    private String getResourceTypeFromRoutingKey(String routingKey) {
+        String[] keyParts =  routingKey.split("\\.");
+        return keyParts[3];
+    }
+
+    private String getResourceUUIDFromRoutingKey(String routingKey) {
+        String[] keyParts =  routingKey.split("\\.");
+        return keyParts[4];
+    }
+
+    @Override
+    public String getName() {
+        return _name;
+    }
+
+    @Override
+    public boolean start() {
+        ReconnectionTask reconnect = new ReconnectionTask(); // initiate connection to AMQP server
+        executorService.submit(reconnect);
+        return true;
+    }
+
+    @Override
+    public boolean stop() {
+
+        if (_connection.isOpen()) {
+            for (String subscriberId : _subscribers.keySet()) {
+                Ternary<String, Channel, EventSubscriber> subscriberDetails = _subscribers.get(subscriberId);
+                Channel channel =  subscriberDetails.second();
+                String queueName = subscriberId;
+                try {
+                    channel.queueDelete(queueName);
+                    channel.abort();
+                } catch (IOException ioe) {
+                    s_logger.warn("Failed to delete queue: " + queueName + " on AMQP server due to " + ioe.getMessage() );
+                }
+            }
+        }
+
+        closeConnection();
+        return true;
+    }
+
+    // logic to deal with loss of connection to AMQP server
+    private class DisconnectHandler implements ShutdownListener {
+
+        @Override
+        public void shutdownCompleted(ShutdownSignalException shutdownSignalException) {
+            if (!shutdownSignalException.isInitiatedByApplication()) {
+
+                for (String subscriberId : _subscribers.keySet()) {
+                    Ternary<String, Channel, EventSubscriber> subscriberDetails = _subscribers.get(subscriberId);
+                    subscriberDetails.second(null);
+                    _subscribers.put(subscriberId, subscriberDetails);
+                }
+
+                abortConnection(); // disconnected to AMQP server, so abort the connection and channels
+                s_logger.warn("Connection has been shutdown by AMQP server. Attempting to reconnect.");
+
+                // initiate re-connect process
+                ReconnectionTask reconnect = new ReconnectionTask();
+                executorService.submit(reconnect);
+            }
+        }
+    }
+
+    // retry logic to connect back to AMQP server after loss of connection
+    private class ReconnectionTask implements Runnable {
+
+        boolean connected = false;
+        Connection connection = null;
+
+        public void run() {
+
+            while (!connected) {
+                try {
+                    Thread.sleep(_retryInterval);
+                } catch (InterruptedException ie) {
+                    // ignore timer interrupts
+                }
+
+                try {
+                    try {
+                        connection = createConnection();
+                        connected = true;
+                    } catch (IOException ie) {
+                        continue; // can't establish connection to AMQP server yet, so continue
+                    }
+
+                    // prepare consumer on AMQP server for each of subscriber
+                    for (String subscriberId : _subscribers.keySet()) {
+                        Ternary<String, Channel, EventSubscriber> subscriberDetails = _subscribers.get(subscriberId);
+                        String bindingKey = subscriberDetails.first();
+                        EventSubscriber subscriber = subscriberDetails.third();
+
+                        /** create a queue with subscriber ID as queue name and bind it to the exchange
+                         *  with binding key formed from event topic
+                         */
+                        Channel channel = createChannel(connection);
+                        createExchange(channel, _amqpExchangeName);
+                        channel.queueDeclare(subscriberId, false, false, false, null);
+                        channel.queueBind(subscriberId, _amqpExchangeName, bindingKey);
+
+                        // register a callback handler to receive the events that a subscriber subscribed to
+                        channel.basicConsume(subscriberId, _autoAck, subscriberId,
+                                new DefaultConsumer(channel) {
+                                    @Override
+                                    public void handleDelivery(String queueName,
+                                                               Envelope envelope,
+                                                               AMQP.BasicProperties properties,
+                                                               byte[] body)
+                                            throws IOException {
+
+                                        Ternary<String, Channel, EventSubscriber> subscriberDetails
+                                                = _subscribers.get(queueName); // queue name == subscriber ID
+
+                                        if (subscriberDetails != null) {
+                                            EventSubscriber subscriber = subscriberDetails.third();
+                                            String routingKey =  envelope.getRoutingKey();
+                                            String eventSource = getEventSourceFromRoutingKey(routingKey);
+                                            String eventCategory = getEventCategoryFromRoutingKey(routingKey);
+                                            String eventType = getEventTypeFromRoutingKey(routingKey);
+                                            String resourceType = getResourceTypeFromRoutingKey(routingKey);
+                                            String resourceUUID = getResourceUUIDFromRoutingKey(routingKey);
+
+                                            // create event object from the message details obtained from AMQP server
+                                            Event event = new Event(eventSource, eventCategory, eventType,
+                                                    resourceType, resourceUUID);
+                                            event.setDescription(new String(body));
+
+                                            // deliver the event to call back object provided by subscriber
+                                            subscriber.onEvent(event);
+                                        }
+                                    }
+                                }
+                        );
+
+                        // update the channel details for the subscription
+                        subscriberDetails.second(channel);
+                        _subscribers.put(subscriberId, subscriberDetails);
+                    }
+                } catch (Exception e) {
+                    s_logger.warn("Failed to recreate queues and binding for the subscribers due to " + e.getMessage());
+                }
+            }
+            return;
+        }
+    }
+}
\ No newline at end of file
diff --git a/plugins/network-elements/ovs/src/com/cloud/network/guru/OvsGuestNetworkGuru.java b/plugins/network-elements/ovs/src/com/cloud/network/guru/OvsGuestNetworkGuru.java
index 30a1129..2104322 100644
--- a/plugins/network-elements/ovs/src/com/cloud/network/guru/OvsGuestNetworkGuru.java
+++ b/plugins/network-elements/ovs/src/com/cloud/network/guru/OvsGuestNetworkGuru.java
@@ -18,6 +18,7 @@
 
 import javax.ejb.Local;
 
+import com.cloud.event.ActionEventUtils;
 import org.apache.log4j.Logger;
 
 import com.cloud.dc.DataCenter;
@@ -25,7 +26,6 @@
 import com.cloud.deploy.DeployDestination;
 import com.cloud.deploy.DeploymentPlan;
 import com.cloud.event.EventTypes;
-import com.cloud.event.EventUtils;
 import com.cloud.event.EventVO;
 import com.cloud.exception.InsufficientVirtualNetworkCapcityException;
 import com.cloud.network.Network;
@@ -95,7 +95,7 @@
                 throw new InsufficientVirtualNetworkCapcityException("Unable to allocate vnet as a part of network " + network + " implement ", DataCenter.class, dcId);
             }
             implemented.setBroadcastUri(BroadcastDomainType.Vswitch.toUri(vnet));
-            EventUtils.saveEvent(UserContext.current().getCallerUserId(), network.getAccountId(), EventVO.LEVEL_INFO, EventTypes.EVENT_ZONE_VLAN_ASSIGN, "Assigned Zone Vlan: "+vnet+ " Network Id: "+network.getId(), 0);
+            ActionEventUtils.onCompletedActionEvent(UserContext.current().getCallerUserId(), network.getAccountId(), EventVO.LEVEL_INFO, EventTypes.EVENT_ZONE_VLAN_ASSIGN, "Assigned Zone Vlan: " + vnet + " Network Id: " + network.getId(), 0);
         } else {
             implemented.setBroadcastUri(network.getBroadcastUri());
         }
diff --git a/plugins/pom.xml b/plugins/pom.xml
index c5b6e58..f91c6ee 100644
--- a/plugins/pom.xml
+++ b/plugins/pom.xml
@@ -41,6 +41,7 @@
     <module>hypervisors/ovm</module>
     <module>hypervisors/xen</module>
     <module>hypervisors/kvm</module>
+    <module>event-bus/rabbitmq</module>
     <module>hypervisors/simulator</module>
     <module>hypervisors/baremetal</module>
     <module>network-elements/elastic-loadbalancer</module>
diff --git a/pom.xml b/pom.xml
index 35d6520..59feef5 100644
--- a/pom.xml
+++ b/pom.xml
@@ -163,6 +163,7 @@
     <module>patches</module>
     <module>client</module>
     <module>test</module>
+    <module>framework</module>
   </modules>
 
   <dependencyManagement>
diff --git a/server/pom.xml b/server/pom.xml
index 4c3ba6f..ef1b68a 100644
--- a/server/pom.xml
+++ b/server/pom.xml
@@ -80,6 +80,11 @@
       <classifier>tests</classifier>
       <scope>test</scope>
     </dependency>
+    <dependency>
+      <groupId>org.apache.cloudstack</groupId>
+      <artifactId>cloud-framework-events</artifactId>
+      <version>${project.version}</version>
+    </dependency>
   </dependencies>
   <build>
     <defaultGoal>install</defaultGoal>
diff --git a/server/src/com/cloud/alert/AlertManagerImpl.java b/server/src/com/cloud/alert/AlertManagerImpl.java
index a4c0fac..1a93f97 100755
--- a/server/src/com/cloud/alert/AlertManagerImpl.java
+++ b/server/src/com/cloud/alert/AlertManagerImpl.java
@@ -59,6 +59,7 @@
 import com.cloud.dc.dao.DataCenterDao;
 import com.cloud.dc.dao.DataCenterIpAddressDao;
 import com.cloud.dc.dao.HostPodDao;
+import com.cloud.event.AlertGenerator;
 import com.cloud.host.Host;
 import com.cloud.host.HostVO;
 import com.cloud.host.dao.HostDao;
@@ -260,6 +261,10 @@
 
     @Override
     public void sendAlert(short alertType, long dataCenterId, Long podId, String subject, String body) {
+
+        // publish alert
+        AlertGenerator.publishAlertOnEventBus(getAlertType(alertType), dataCenterId, podId, subject, body);
+
         // TODO:  queue up these messages and send them as one set of issues once a certain number of issues is reached?  If that's the case,
         //         shouldn't we have a type/severity as part of the API so that severe errors get sent right away?
         try {
@@ -271,6 +276,65 @@
         }
     }
 
+    private String getAlertType(short alertType) {
+        if (alertType == ALERT_TYPE_MEMORY) {
+            return "ALERT.MEMORY";
+        } else if (alertType == ALERT_TYPE_CPU) {
+            return "ALERT.MEMORY";
+        } else if (alertType == ALERT_TYPE_STORAGE) {
+            return "ALERT.STORAGE";
+        } else if (alertType == ALERT_TYPE_STORAGE_ALLOCATED) {
+            return "ALERT.STORAGE.ALLOCATED";
+        } else if (alertType == ALERT_TYPE_VIRTUAL_NETWORK_PUBLIC_IP) {
+            return "ALERT.NETWORK.PUBLICIP";
+        } else if (alertType == ALERT_TYPE_PRIVATE_IP) {
+            return "ALERT.NETWORK.PRIVATEIP";
+        } else if (alertType == ALERT_TYPE_SECONDARY_STORAGE) {
+            return "ALERT.STORAGE.SECONDARY";
+        } else if (alertType == ALERT_TYPE_HOST) {
+            return "ALERT.COMPUTE.HOST";
+        } else if (alertType == ALERT_TYPE_USERVM) {
+            return "ALERT.USERVM";
+        } else if (alertType == ALERT_TYPE_DOMAIN_ROUTER) {
+            return "ALERT.SERVICE.DOMAINROUTER";
+        } else if (alertType == ALERT_TYPE_CONSOLE_PROXY) {
+            return "ALERT.SERVICE.CONSOLEPROXY";
+        } else if (alertType == ALERT_TYPE_ROUTING) {
+            return "ALERT.NETWORK.ROUTING";
+        } else if (alertType == ALERT_TYPE_STORAGE_MISC) {
+            return "ALERT.STORAGE.MISC";
+        } else if (alertType == ALERT_TYPE_USAGE_SERVER) {
+            return "ALERT.USAGE";
+        } else if (alertType == ALERT_TYPE_MANAGMENT_NODE) {
+            return "ALERT.MANAGEMENT";
+        } else if (alertType == ALERT_TYPE_DOMAIN_ROUTER_MIGRATE) {
+            return "ALERT.NETWORK.DOMAINROUTERMIGRATE";
+        } else if (alertType == ALERT_TYPE_CONSOLE_PROXY_MIGRATE) {
+            return "ALERT.SERVICE.CONSOLEPROXYMIGRATE";
+        } else if (alertType == ALERT_TYPE_USERVM_MIGRATE) {
+            return "ALERT.USERVM.MIGRATE";
+        } else if (alertType == ALERT_TYPE_VLAN) {
+            return "ALERT.NETWORK.VLAN";
+        } else if (alertType == ALERT_TYPE_SSVM) {
+            return "ALERT.SERVICE.SSVM";
+        } else if (alertType == ALERT_TYPE_USAGE_SERVER_RESULT) {
+            return "ALERT.USAGE.RESULT";
+        } else if (alertType == ALERT_TYPE_STORAGE_DELETE) {
+            return "ALERT.STORAGE.DELETE";
+        } else if (alertType == ALERT_TYPE_UPDATE_RESOURCE_COUNT) {
+            return "ALERT.RESOURCE.COUNT";
+        } else if (alertType == ALERT_TYPE_USAGE_SANITY_RESULT) {
+            return "ALERT.USAGE.SANITY";
+        } else if (alertType == ALERT_TYPE_DIRECT_ATTACHED_PUBLIC_IP) {
+            return "ALERT.NETWORK.DIRECTPUBLICIP";
+        } else if (alertType == ALERT_TYPE_LOCAL_STORAGE) {
+            return "ALERT.STORAGE.LOCAL";
+        } else if (alertType == ALERT_TYPE_RESOURCE_LIMIT_EXCEEDED) {
+            return "ALERT.RESOURCE.EXCEED";
+        }
+        return "UNKNOWN";
+    }
+
     @Override @DB
     public void recalculateCapacity() {
         // FIXME: the right way to do this is to register a listener (see RouterStatsListener, VMSyncListener)
diff --git a/server/src/com/cloud/api/ApiDBUtils.java b/server/src/com/cloud/api/ApiDBUtils.java
index 0b08b26..143e280 100755
--- a/server/src/com/cloud/api/ApiDBUtils.java
+++ b/server/src/com/cloud/api/ApiDBUtils.java
@@ -16,68 +16,8 @@
 // under the License.
 package com.cloud.api;
 
-import java.util.ArrayList;
-import java.util.EnumSet;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-
-import org.apache.cloudstack.api.ApiConstants.HostDetails;
-import org.apache.cloudstack.api.ApiConstants.VMDetails;
-import org.apache.cloudstack.api.response.AccountResponse;
-import org.apache.cloudstack.api.response.AsyncJobResponse;
-import org.apache.cloudstack.api.response.DiskOfferingResponse;
-import org.apache.cloudstack.api.response.DomainRouterResponse;
-import org.apache.cloudstack.api.response.EventResponse;
-import org.apache.cloudstack.api.response.HostResponse;
-import org.apache.cloudstack.api.response.InstanceGroupResponse;
-import org.apache.cloudstack.api.response.ProjectAccountResponse;
-import org.apache.cloudstack.api.response.ProjectInvitationResponse;
-import org.apache.cloudstack.api.response.ProjectResponse;
-import org.apache.cloudstack.api.response.ResourceTagResponse;
-import org.apache.cloudstack.api.response.SecurityGroupResponse;
-import org.apache.cloudstack.api.response.ServiceOfferingResponse;
-import org.apache.cloudstack.api.response.StoragePoolResponse;
-import org.apache.cloudstack.api.response.UserResponse;
-import org.apache.cloudstack.api.response.UserVmResponse;
-import org.apache.cloudstack.api.response.VolumeResponse;
-import org.apache.cloudstack.api.response.ZoneResponse;
-
-import com.cloud.api.query.dao.AccountJoinDao;
-import com.cloud.api.query.dao.AsyncJobJoinDao;
-import com.cloud.api.query.dao.DataCenterJoinDao;
-import com.cloud.api.query.dao.DiskOfferingJoinDao;
-import com.cloud.api.query.dao.DomainRouterJoinDao;
-import com.cloud.api.query.dao.HostJoinDao;
-import com.cloud.api.query.dao.InstanceGroupJoinDao;
-import com.cloud.api.query.dao.ProjectAccountJoinDao;
-import com.cloud.api.query.dao.ProjectInvitationJoinDao;
-import com.cloud.api.query.dao.ProjectJoinDao;
-import com.cloud.api.query.dao.ResourceTagJoinDao;
-import com.cloud.api.query.dao.SecurityGroupJoinDao;
-import com.cloud.api.query.dao.ServiceOfferingJoinDao;
-import com.cloud.api.query.dao.StoragePoolJoinDao;
-import com.cloud.api.query.dao.UserAccountJoinDao;
-import com.cloud.api.query.dao.UserVmJoinDao;
-import com.cloud.api.query.dao.VolumeJoinDao;
-import com.cloud.api.query.vo.AccountJoinVO;
-import com.cloud.api.query.vo.AsyncJobJoinVO;
-import com.cloud.api.query.vo.DataCenterJoinVO;
-import com.cloud.api.query.vo.DiskOfferingJoinVO;
-import com.cloud.api.query.vo.DomainRouterJoinVO;
-import com.cloud.api.query.vo.EventJoinVO;
-import com.cloud.api.query.vo.HostJoinVO;
-import com.cloud.api.query.vo.InstanceGroupJoinVO;
-import com.cloud.api.query.vo.ProjectAccountJoinVO;
-import com.cloud.api.query.vo.ProjectInvitationJoinVO;
-import com.cloud.api.query.vo.ProjectJoinVO;
-import com.cloud.api.query.vo.ResourceTagJoinVO;
-import com.cloud.api.query.vo.SecurityGroupJoinVO;
-import com.cloud.api.query.vo.ServiceOfferingJoinVO;
-import com.cloud.api.query.vo.StoragePoolJoinVO;
-import com.cloud.api.query.vo.UserAccountJoinVO;
-import com.cloud.api.query.vo.UserVmJoinVO;
-import com.cloud.api.query.vo.VolumeJoinVO;
+import com.cloud.api.query.dao.*;
+import com.cloud.api.query.vo.*;
 import com.cloud.async.AsyncJob;
 import com.cloud.async.AsyncJobManager;
 import com.cloud.async.AsyncJobVO;
@@ -89,18 +29,8 @@
 import com.cloud.configuration.ConfigurationService;
 import com.cloud.configuration.Resource.ResourceType;
 import com.cloud.configuration.dao.ConfigurationDao;
-import com.cloud.dc.AccountVlanMapVO;
-import com.cloud.dc.ClusterVO;
-import com.cloud.dc.DataCenter;
-import com.cloud.dc.DataCenterVO;
-import com.cloud.dc.HostPodVO;
-import com.cloud.dc.Vlan;
-import com.cloud.dc.VlanVO;
-import com.cloud.dc.dao.AccountVlanMapDao;
-import com.cloud.dc.dao.ClusterDao;
-import com.cloud.dc.dao.DataCenterDao;
-import com.cloud.dc.dao.HostPodDao;
-import com.cloud.dc.dao.VlanDao;
+import com.cloud.dc.*;
+import com.cloud.dc.dao.*;
 import com.cloud.domain.DomainVO;
 import com.cloud.domain.dao.DomainDao;
 import com.cloud.event.Event;
@@ -112,65 +42,23 @@
 import com.cloud.host.HostVO;
 import com.cloud.host.dao.HostDao;
 import com.cloud.hypervisor.Hypervisor.HypervisorType;
-import com.cloud.network.IPAddressVO;
-import com.cloud.network.IpAddress;
-import com.cloud.network.LoadBalancerVO;
-import com.cloud.network.Network;
+import com.cloud.network.*;
 import com.cloud.network.Network.Capability;
 import com.cloud.network.Network.Provider;
 import com.cloud.network.Network.Service;
-import com.cloud.network.NetworkDomainVO;
-import com.cloud.network.NetworkManager;
-import com.cloud.network.NetworkModel;
-import com.cloud.network.NetworkProfile;
-import com.cloud.network.NetworkRuleConfigVO;
-import com.cloud.network.NetworkVO;
-import com.cloud.network.PhysicalNetworkServiceProvider;
-import com.cloud.network.PhysicalNetworkVO;
-import com.cloud.network.Site2SiteVpnGatewayVO;
-import com.cloud.network.Site2SiteCustomerGatewayVO;
 import com.cloud.network.Networks.TrafficType;
-import com.cloud.network.as.AutoScalePolicy;
-import com.cloud.network.as.AutoScalePolicyConditionMapVO;
-import com.cloud.network.as.AutoScalePolicyVO;
-import com.cloud.network.as.AutoScaleVmGroupPolicyMapVO;
-import com.cloud.network.as.AutoScaleVmGroupVO;
-import com.cloud.network.as.AutoScaleVmProfileVO;
-import com.cloud.network.as.ConditionVO;
-import com.cloud.network.as.CounterVO;
-import com.cloud.network.as.dao.AutoScalePolicyConditionMapDao;
-import com.cloud.network.as.dao.AutoScalePolicyDao;
-import com.cloud.network.as.dao.AutoScaleVmGroupDao;
-import com.cloud.network.as.dao.AutoScaleVmGroupPolicyMapDao;
-import com.cloud.network.as.dao.AutoScaleVmProfileDao;
-import com.cloud.network.as.dao.ConditionDao;
-import com.cloud.network.as.dao.CounterDao;
-import com.cloud.network.dao.FirewallRulesCidrsDao;
-import com.cloud.network.dao.FirewallRulesDao;
-import com.cloud.network.dao.IPAddressDao;
-import com.cloud.network.dao.LoadBalancerDao;
-import com.cloud.network.dao.NetworkDao;
-import com.cloud.network.dao.PhysicalNetworkDao;
-import com.cloud.network.dao.NetworkDomainDao;
-import com.cloud.network.dao.NetworkRuleConfigDao;
-import com.cloud.network.dao.PhysicalNetworkServiceProviderDao;
-import com.cloud.network.dao.PhysicalNetworkServiceProviderVO;
-import com.cloud.network.dao.PhysicalNetworkTrafficTypeDao;
-import com.cloud.network.dao.PhysicalNetworkTrafficTypeVO;
-import com.cloud.network.dao.Site2SiteVpnGatewayDao;
-import com.cloud.network.dao.Site2SiteCustomerGatewayDao;
+import com.cloud.network.as.*;
+import com.cloud.network.as.dao.*;
+import com.cloud.network.dao.*;
 import com.cloud.network.router.VirtualRouter;
 import com.cloud.network.rules.FirewallRuleVO;
 import com.cloud.network.security.SecurityGroup;
 import com.cloud.network.security.SecurityGroupManager;
 import com.cloud.network.security.SecurityGroupVO;
 import com.cloud.network.security.dao.SecurityGroupDao;
-import com.cloud.network.vpc.StaticRouteVO;
-import com.cloud.network.vpc.VpcGatewayVO;
-import com.cloud.network.vpc.VpcManager;
-import com.cloud.network.vpc.VpcOffering;
-import com.cloud.network.vpc.VpcVO;
+import com.cloud.network.vpc.*;
 import com.cloud.network.vpc.dao.StaticRouteDao;
+import com.cloud.network.vpc.dao.VpcDao;
 import com.cloud.network.vpc.dao.VpcGatewayDao;
 import com.cloud.network.vpc.dao.VpcOfferingDao;
 import com.cloud.offering.DiskOffering;
@@ -183,57 +71,16 @@
 import com.cloud.projects.ProjectInvitation;
 import com.cloud.projects.ProjectService;
 import com.cloud.resource.ResourceManager;
-import com.cloud.server.Criteria;
-import com.cloud.server.ManagementServer;
-import com.cloud.server.ResourceTag;
+import com.cloud.server.*;
 import com.cloud.server.ResourceTag.TaggedResourceType;
-import com.cloud.server.StatsCollector;
-import com.cloud.server.TaggedResourceService;
 import com.cloud.service.ServiceOfferingVO;
 import com.cloud.service.dao.ServiceOfferingDao;
-import com.cloud.storage.DiskOfferingVO;
-import com.cloud.storage.GuestOS;
-import com.cloud.storage.GuestOSCategoryVO;
-import com.cloud.storage.Snapshot;
-import com.cloud.storage.SnapshotVO;
+import com.cloud.storage.*;
 import com.cloud.storage.Storage.ImageFormat;
-import com.cloud.storage.StorageManager;
-import com.cloud.storage.StoragePool;
-import com.cloud.storage.StoragePoolVO;
-import com.cloud.storage.StorageStats;
-import com.cloud.storage.UploadVO;
-import com.cloud.storage.VMTemplateHostVO;
-import com.cloud.storage.VMTemplateS3VO;
-import com.cloud.storage.VMTemplateSwiftVO;
-import com.cloud.storage.VMTemplateVO;
-import com.cloud.storage.Volume;
 import com.cloud.storage.Volume.Type;
-import com.cloud.storage.VolumeHostVO;
-import com.cloud.storage.VolumeVO;
-import com.cloud.storage.dao.DiskOfferingDao;
-import com.cloud.storage.dao.GuestOSCategoryDao;
-import com.cloud.storage.dao.GuestOSDao;
-import com.cloud.storage.dao.SnapshotDao;
-import com.cloud.storage.dao.SnapshotPolicyDao;
-import com.cloud.storage.dao.StoragePoolDao;
-import com.cloud.storage.dao.UploadDao;
-import com.cloud.storage.dao.VMTemplateDao;
-import com.cloud.storage.dao.VMTemplateDetailsDao;
-import com.cloud.storage.dao.VMTemplateHostDao;
-import com.cloud.storage.dao.VMTemplateS3Dao;
-import com.cloud.storage.dao.VMTemplateSwiftDao;
-import com.cloud.storage.dao.VolumeDao;
-import com.cloud.storage.dao.VolumeHostDao;
+import com.cloud.storage.dao.*;
 import com.cloud.storage.snapshot.SnapshotPolicy;
-import com.cloud.user.Account;
-import com.cloud.user.AccountDetailsDao;
-import com.cloud.user.AccountVO;
-import com.cloud.user.ResourceLimitService;
-import com.cloud.user.SSHKeyPairVO;
-import com.cloud.user.User;
-import com.cloud.user.UserAccount;
-import com.cloud.user.UserStatisticsVO;
-import com.cloud.user.UserVO;
+import com.cloud.user.*;
 import com.cloud.user.dao.AccountDao;
 import com.cloud.user.dao.SSHKeyPairDao;
 import com.cloud.user.dao.UserDao;
@@ -242,23 +89,13 @@
 import com.cloud.utils.NumbersUtil;
 import com.cloud.utils.Pair;
 import com.cloud.utils.component.ComponentLocator;
-import com.cloud.vm.ConsoleProxyVO;
-import com.cloud.vm.DomainRouterVO;
-import com.cloud.vm.InstanceGroup;
-import com.cloud.vm.InstanceGroupVO;
-import com.cloud.vm.NicProfile;
-import com.cloud.vm.UserVmDetailVO;
-import com.cloud.vm.UserVmManager;
-import com.cloud.vm.UserVmVO;
-import com.cloud.vm.VMInstanceVO;
-import com.cloud.vm.VirtualMachine;
-import com.cloud.vm.VmStats;
-import com.cloud.vm.dao.ConsoleProxyDao;
-import com.cloud.vm.dao.DomainRouterDao;
-import com.cloud.vm.dao.UserVmDao;
-import com.cloud.vm.dao.UserVmDetailsDao;
-import com.cloud.vm.dao.VMInstanceDao;
-import com.cloud.network.vpc.dao.VpcDao;
+import com.cloud.vm.*;
+import com.cloud.vm.dao.*;
+import org.apache.cloudstack.api.ApiConstants.HostDetails;
+import org.apache.cloudstack.api.ApiConstants.VMDetails;
+import org.apache.cloudstack.api.response.*;
+
+import java.util.*;
 
 public class ApiDBUtils {
     private static ManagementServer _ms;
@@ -699,7 +536,7 @@
 
     public static Snapshot findSnapshotById(long snapshotId) {
         SnapshotVO snapshot = _snapshotDao.findById(snapshotId);
-        if (snapshot != null && snapshot.getRemoved() == null && snapshot.getStatus() == Snapshot.Status.BackedUp) {
+        if (snapshot != null && snapshot.getRemoved() == null && snapshot.getState() == Snapshot.State.BackedUp) {
             return snapshot;
         } else {
             return null;
diff --git a/server/src/com/cloud/api/ApiResponseHelper.java b/server/src/com/cloud/api/ApiResponseHelper.java
index 641f25b..54639a8 100755
--- a/server/src/com/cloud/api/ApiResponseHelper.java
+++ b/server/src/com/cloud/api/ApiResponseHelper.java
@@ -16,125 +16,9 @@
 // under the License.
 package com.cloud.api;
 
-import static java.util.Collections.emptyList;
-import static java.util.Collections.singletonList;
-
-import java.text.DecimalFormat;
-import java.util.ArrayList;
-import java.util.EnumSet;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-import java.util.StringTokenizer;
-
-import org.apache.cloudstack.api.BaseCmd;
-import org.apache.cloudstack.api.ResponseGenerator;
-import org.apache.log4j.Logger;
-
-import org.apache.cloudstack.acl.ControlledEntity;
-import org.apache.cloudstack.acl.ControlledEntity.ACLType;
-import org.apache.cloudstack.api.ApiConstants.HostDetails;
-import org.apache.cloudstack.api.ApiConstants.VMDetails;
-import org.apache.cloudstack.api.command.user.job.QueryAsyncJobResultCmd;
-import org.apache.cloudstack.api.response.AccountResponse;
-
 import com.cloud.api.query.ViewResponseHelper;
-import com.cloud.api.query.vo.AccountJoinVO;
-import com.cloud.api.query.vo.AsyncJobJoinVO;
-import com.cloud.api.query.vo.ControlledViewEntity;
-import com.cloud.api.query.vo.DataCenterJoinVO;
-import com.cloud.api.query.vo.DiskOfferingJoinVO;
-import com.cloud.api.query.vo.DomainRouterJoinVO;
-import com.cloud.api.query.vo.EventJoinVO;
-import com.cloud.api.query.vo.HostJoinVO;
-import com.cloud.api.query.vo.InstanceGroupJoinVO;
-import com.cloud.api.query.vo.ProjectAccountJoinVO;
-import com.cloud.api.query.vo.ProjectInvitationJoinVO;
-import com.cloud.api.query.vo.ProjectJoinVO;
-import com.cloud.api.query.vo.ResourceTagJoinVO;
-import com.cloud.api.query.vo.SecurityGroupJoinVO;
-import com.cloud.api.query.vo.ServiceOfferingJoinVO;
-import com.cloud.api.query.vo.StoragePoolJoinVO;
-import com.cloud.api.query.vo.UserAccountJoinVO;
-import com.cloud.api.query.vo.UserVmJoinVO;
-import com.cloud.api.query.vo.VolumeJoinVO;
+import com.cloud.api.query.vo.*;
 import com.cloud.api.response.ApiResponseSerializer;
-import org.apache.cloudstack.api.response.AsyncJobResponse;
-import org.apache.cloudstack.api.response.AutoScalePolicyResponse;
-import org.apache.cloudstack.api.response.AutoScaleVmGroupResponse;
-import org.apache.cloudstack.api.response.AutoScaleVmProfileResponse;
-import org.apache.cloudstack.api.response.CapabilityResponse;
-import org.apache.cloudstack.api.response.CapacityResponse;
-import org.apache.cloudstack.api.response.ClusterResponse;
-import org.apache.cloudstack.api.response.ConditionResponse;
-import org.apache.cloudstack.api.response.ConfigurationResponse;
-import org.apache.cloudstack.api.response.ControlledEntityResponse;
-import org.apache.cloudstack.api.response.CounterResponse;
-import org.apache.cloudstack.api.response.CreateCmdResponse;
-import org.apache.cloudstack.api.response.DiskOfferingResponse;
-import org.apache.cloudstack.api.response.DomainResponse;
-import org.apache.cloudstack.api.response.DomainRouterResponse;
-import org.apache.cloudstack.api.response.EventResponse;
-import org.apache.cloudstack.api.response.ExtractResponse;
-import org.apache.cloudstack.api.response.FirewallResponse;
-import org.apache.cloudstack.api.response.FirewallRuleResponse;
-import org.apache.cloudstack.api.response.GuestOSResponse;
-import org.apache.cloudstack.api.response.HostResponse;
-import org.apache.cloudstack.api.response.HypervisorCapabilitiesResponse;
-import org.apache.cloudstack.api.response.ControlledViewEntityResponse;
-import org.apache.cloudstack.api.response.IPAddressResponse;
-import org.apache.cloudstack.api.response.InstanceGroupResponse;
-import org.apache.cloudstack.api.response.IpForwardingRuleResponse;
-import org.apache.cloudstack.api.response.LBStickinessPolicyResponse;
-import org.apache.cloudstack.api.response.LBStickinessResponse;
-import org.apache.cloudstack.api.response.LDAPConfigResponse;
-import org.apache.cloudstack.api.response.LoadBalancerResponse;
-import org.apache.cloudstack.api.response.NetworkACLResponse;
-import org.apache.cloudstack.api.response.NetworkOfferingResponse;
-import org.apache.cloudstack.api.response.NetworkResponse;
-import org.apache.cloudstack.api.response.PhysicalNetworkResponse;
-import org.apache.cloudstack.api.response.PodResponse;
-import org.apache.cloudstack.api.response.PrivateGatewayResponse;
-import org.apache.cloudstack.api.response.ProjectAccountResponse;
-import org.apache.cloudstack.api.response.ProjectInvitationResponse;
-import org.apache.cloudstack.api.response.ProjectResponse;
-import org.apache.cloudstack.api.response.ProviderResponse;
-import org.apache.cloudstack.api.response.RemoteAccessVpnResponse;
-import org.apache.cloudstack.api.response.ResourceCountResponse;
-import org.apache.cloudstack.api.response.ResourceLimitResponse;
-import org.apache.cloudstack.api.response.ResourceTagResponse;
-import org.apache.cloudstack.api.response.SecurityGroupResponse;
-import org.apache.cloudstack.api.response.SecurityGroupRuleResponse;
-import org.apache.cloudstack.api.response.ServiceOfferingResponse;
-import org.apache.cloudstack.api.response.ServiceResponse;
-import org.apache.cloudstack.api.response.Site2SiteCustomerGatewayResponse;
-import org.apache.cloudstack.api.response.Site2SiteVpnConnectionResponse;
-import org.apache.cloudstack.api.response.Site2SiteVpnGatewayResponse;
-import org.apache.cloudstack.api.response.SnapshotPolicyResponse;
-import org.apache.cloudstack.api.response.SnapshotResponse;
-import org.apache.cloudstack.api.response.SnapshotScheduleResponse;
-import org.apache.cloudstack.api.response.StaticRouteResponse;
-import org.apache.cloudstack.api.response.StorageNetworkIpRangeResponse;
-import org.apache.cloudstack.api.response.StoragePoolResponse;
-import org.apache.cloudstack.api.response.SwiftResponse;
-import org.apache.cloudstack.api.response.SystemVmInstanceResponse;
-import org.apache.cloudstack.api.response.SystemVmResponse;
-import org.apache.cloudstack.api.response.TemplatePermissionsResponse;
-import org.apache.cloudstack.api.response.TemplateResponse;
-import org.apache.cloudstack.api.response.TrafficTypeResponse;
-import org.apache.cloudstack.api.response.UserResponse;
-import org.apache.cloudstack.api.response.UserVmResponse;
-import org.apache.cloudstack.api.response.VirtualRouterProviderResponse;
-import org.apache.cloudstack.api.response.VlanIpRangeResponse;
-import org.apache.cloudstack.api.response.VolumeResponse;
-import org.apache.cloudstack.api.response.VpcOfferingResponse;
-import org.apache.cloudstack.api.response.VpcResponse;
-import org.apache.cloudstack.api.response.VpnUsersResponse;
-import org.apache.cloudstack.api.response.ZoneResponse;
-
-import org.apache.cloudstack.api.response.S3Response;
 import com.cloud.async.AsyncJob;
 import com.cloud.capacity.Capacity;
 import com.cloud.capacity.CapacityVO;
@@ -143,53 +27,21 @@
 import com.cloud.configuration.Resource.ResourceOwnerType;
 import com.cloud.configuration.ResourceCount;
 import com.cloud.configuration.ResourceLimit;
-import com.cloud.dc.ClusterVO;
-import com.cloud.dc.DataCenter;
-import com.cloud.dc.DataCenterVO;
-import com.cloud.dc.HostPodVO;
-import com.cloud.dc.Pod;
-import com.cloud.dc.StorageNetworkIpRange;
-import com.cloud.dc.Vlan;
+import com.cloud.dc.*;
 import com.cloud.dc.Vlan.VlanType;
-import com.cloud.dc.VlanVO;
 import com.cloud.domain.Domain;
 import com.cloud.event.Event;
 import com.cloud.host.Host;
 import com.cloud.host.HostVO;
 import com.cloud.hypervisor.HypervisorCapabilities;
-import com.cloud.network.IPAddressVO;
-import com.cloud.network.IpAddress;
-import com.cloud.network.Network;
+import com.cloud.network.*;
 import com.cloud.network.Network.Capability;
 import com.cloud.network.Network.Provider;
 import com.cloud.network.Network.Service;
-import com.cloud.network.NetworkProfile;
-import com.cloud.network.NetworkVO;
 import com.cloud.network.Networks.TrafficType;
-import com.cloud.network.PhysicalNetwork;
-import com.cloud.network.PhysicalNetworkServiceProvider;
-import com.cloud.network.PhysicalNetworkTrafficType;
-import com.cloud.network.PhysicalNetworkVO;
-import com.cloud.network.RemoteAccessVpn;
-import com.cloud.network.Site2SiteCustomerGateway;
-import com.cloud.network.Site2SiteVpnConnection;
-import com.cloud.network.Site2SiteVpnGateway;
-import com.cloud.network.VirtualRouterProvider;
-import com.cloud.network.VpnUser;
-import com.cloud.network.as.AutoScalePolicy;
-import com.cloud.network.as.AutoScaleVmGroup;
-import com.cloud.network.as.AutoScaleVmProfile;
-import com.cloud.network.as.AutoScaleVmProfileVO;
-import com.cloud.network.as.Condition;
-import com.cloud.network.as.ConditionVO;
-import com.cloud.network.as.Counter;
+import com.cloud.network.as.*;
 import com.cloud.network.router.VirtualRouter;
-import com.cloud.network.rules.FirewallRule;
-import com.cloud.network.rules.FirewallRuleVO;
-import com.cloud.network.rules.LoadBalancer;
-import com.cloud.network.rules.PortForwardingRule;
-import com.cloud.network.rules.StaticNatRule;
-import com.cloud.network.rules.StickinessPolicy;
+import com.cloud.network.rules.*;
 import com.cloud.network.security.SecurityGroup;
 import com.cloud.network.security.SecurityRule;
 import com.cloud.network.security.SecurityRule.SecurityRuleType;
@@ -207,25 +59,11 @@
 import com.cloud.server.Criteria;
 import com.cloud.server.ResourceTag;
 import com.cloud.server.ResourceTag.TaggedResourceType;
-import com.cloud.storage.GuestOS;
-import com.cloud.storage.GuestOSCategoryVO;
-import com.cloud.storage.S3;
-import com.cloud.storage.Snapshot;
+import com.cloud.storage.*;
 import com.cloud.storage.Storage.ImageFormat;
 import com.cloud.storage.Storage.StoragePoolType;
 import com.cloud.storage.Storage.TemplateType;
-import com.cloud.storage.StoragePool;
-import com.cloud.storage.StoragePoolVO;
-import com.cloud.storage.StorageStats;
-import com.cloud.storage.Swift;
-import com.cloud.storage.UploadVO;
-import com.cloud.storage.VMTemplateHostVO;
-import com.cloud.storage.VMTemplateS3VO;
 import com.cloud.storage.VMTemplateStorageResourceAssoc.Status;
-import com.cloud.storage.VMTemplateSwiftVO;
-import com.cloud.storage.VMTemplateVO;
-import com.cloud.storage.Volume;
-import com.cloud.storage.VolumeVO;
 import com.cloud.storage.snapshot.SnapshotPolicy;
 import com.cloud.storage.snapshot.SnapshotSchedule;
 import com.cloud.template.VirtualMachineTemplate;
@@ -242,6 +80,21 @@
 import com.cloud.vm.NicProfile;
 import com.cloud.vm.VirtualMachine;
 import com.cloud.vm.VirtualMachine.Type;
+import org.apache.cloudstack.acl.ControlledEntity;
+import org.apache.cloudstack.acl.ControlledEntity.ACLType;
+import org.apache.cloudstack.api.ApiConstants.HostDetails;
+import org.apache.cloudstack.api.ApiConstants.VMDetails;
+import org.apache.cloudstack.api.BaseCmd;
+import org.apache.cloudstack.api.ResponseGenerator;
+import org.apache.cloudstack.api.command.user.job.QueryAsyncJobResultCmd;
+import org.apache.cloudstack.api.response.*;
+import org.apache.log4j.Logger;
+
+import java.text.DecimalFormat;
+import java.util.*;
+
+import static java.util.Collections.emptyList;
+import static java.util.Collections.singletonList;
 
 public class ApiResponseHelper implements ResponseGenerator {
 
@@ -378,7 +231,7 @@
         snapshotResponse.setCreated(snapshot.getCreated());
         snapshotResponse.setName(snapshot.getName());
         snapshotResponse.setIntervalType(ApiDBUtils.getSnapshotIntervalTypes(snapshot.getId()));
-        snapshotResponse.setState(snapshot.getStatus());
+        snapshotResponse.setState(snapshot.getState());
 
         //set tag information
         List<? extends ResourceTag> tags = ApiDBUtils.listByResourceTypeAndId(TaggedResourceType.Snapshot, snapshot.getId());
diff --git a/server/src/com/cloud/api/ApiServer.java b/server/src/com/cloud/api/ApiServer.java
index ed27200..b4612ae 100755
--- a/server/src/com/cloud/api/ApiServer.java
+++ b/server/src/com/cloud/api/ApiServer.java
@@ -50,10 +50,10 @@
 import javax.servlet.http.HttpServletResponse;
 import javax.servlet.http.HttpSession;
 
+import com.cloud.event.ActionEventUtils;
 import com.cloud.utils.ReflectUtil;
 import org.apache.cloudstack.acl.APILimitChecker;
 import org.apache.cloudstack.acl.APIChecker;
-import org.apache.cloudstack.acl.RoleType;
 import org.apache.cloudstack.api.*;
 import org.apache.cloudstack.api.command.user.account.ListAccountsCmd;
 import org.apache.cloudstack.api.command.user.account.ListProjectAccountsCmd;
@@ -116,7 +116,6 @@
 import com.cloud.configuration.dao.ConfigurationDao;
 import com.cloud.domain.Domain;
 import com.cloud.domain.DomainVO;
-import com.cloud.event.EventUtils;
 import com.cloud.exception.AccountLimitException;
 import com.cloud.exception.CloudAuthenticationException;
 import com.cloud.exception.InsufficientCapacityException;
@@ -467,7 +466,7 @@
             asyncCmd.setStartEventId(startEventId);
 
             // save the scheduled event
-            Long eventId = EventUtils.saveScheduledEvent((callerUserId == null) ? User.UID_SYSTEM : callerUserId,
+            Long eventId = ActionEventUtils.onScheduledActionEvent((callerUserId == null) ? User.UID_SYSTEM : callerUserId,
                     asyncCmd.getEntityOwnerId(), asyncCmd.getEventType(), asyncCmd.getEventDescription(),
                     startEventId);
             if (startEventId == 0) {
diff --git a/server/src/com/cloud/baremetal/BareMetalTemplateAdapter.java b/server/src/com/cloud/baremetal/BareMetalTemplateAdapter.java
index 25298a9..74200e2 100755
--- a/server/src/com/cloud/baremetal/BareMetalTemplateAdapter.java
+++ b/server/src/com/cloud/baremetal/BareMetalTemplateAdapter.java
@@ -16,20 +16,10 @@
 // under the License.
 package com.cloud.baremetal;
 
-import java.util.Date;
-import java.util.List;
-
-import javax.ejb.Local;
-
-import org.apache.cloudstack.api.command.user.iso.DeleteIsoCmd;
-import org.apache.cloudstack.api.command.user.iso.RegisterIsoCmd;
-import org.apache.cloudstack.api.command.user.template.RegisterTemplateCmd;
-import org.apache.log4j.Logger;
-
 import com.cloud.configuration.Resource.ResourceType;
 import com.cloud.dc.DataCenterVO;
 import com.cloud.event.EventTypes;
-import com.cloud.event.UsageEventVO;
+import com.cloud.event.UsageEventUtils;
 import com.cloud.exception.ResourceAllocationException;
 import com.cloud.host.Host;
 import com.cloud.host.HostVO;
@@ -46,6 +36,14 @@
 import com.cloud.utils.component.Inject;
 import com.cloud.utils.db.DB;
 import com.cloud.utils.exception.CloudRuntimeException;
+import org.apache.cloudstack.api.command.user.iso.DeleteIsoCmd;
+import org.apache.cloudstack.api.command.user.iso.RegisterIsoCmd;
+import org.apache.cloudstack.api.command.user.template.RegisterTemplateCmd;
+import org.apache.log4j.Logger;
+
+import javax.ejb.Local;
+import java.util.Date;
+import java.util.List;
 
 @Local(value=TemplateAdapter.class)
 public class BareMetalTemplateAdapter extends TemplateAdapterBase implements TemplateAdapter {
@@ -82,9 +80,9 @@
 	
 	private void templateCreateUsage(VMTemplateVO template, HostVO host) {
 		if (template.getAccountId() != Account.ACCOUNT_ID_SYSTEM) {
-			UsageEventVO usageEvent = new UsageEventVO(EventTypes.EVENT_TEMPLATE_CREATE, template.getAccountId(), host.getDataCenterId(),
-					template.getId(), template.getName(), null, template.getSourceTemplateId(), 0L);
-			_usageEventDao.persist(usageEvent);
+            UsageEventUtils.publishUsageEvent(EventTypes.EVENT_TEMPLATE_CREATE, template.getAccountId(), host.getDataCenterId(),
+                    template.getId(), template.getName(), null, template.getSourceTemplateId(), 0L,
+                    template.getClass().getName(), template.getUuid());
 		}
 	}
 	
@@ -172,8 +170,8 @@
 					_tmpltZoneDao.remove(templateZone.getId());
 				}
 
-				UsageEventVO usageEvent = new UsageEventVO(eventType, account.getId(), pxeServer.getDataCenterId(), templateId, null);
-				_usageEventDao.persist(usageEvent);
+                UsageEventUtils.publishUsageEvent(eventType, account.getId(), pxeServer.getDataCenterId(),
+                        templateId, null, template.getClass().getName(), template.getUuid());
 			} finally {
 				if (lock != null) {
 					_tmpltHostDao.releaseFromLockTable(lock.getId());
diff --git a/server/src/com/cloud/baremetal/BareMetalVmManagerImpl.java b/server/src/com/cloud/baremetal/BareMetalVmManagerImpl.java
index 57cfb39..6ff37ea 100755
--- a/server/src/com/cloud/baremetal/BareMetalVmManagerImpl.java
+++ b/server/src/com/cloud/baremetal/BareMetalVmManagerImpl.java
@@ -16,28 +16,11 @@
 // under the License.
 package com.cloud.baremetal;
 
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.concurrent.Executors;
-
-import javax.ejb.Local;
-import javax.naming.ConfigurationException;
-
-import org.apache.cloudstack.api.command.user.template.CreateTemplateCmd;
-import org.apache.cloudstack.api.command.user.vm.DeployVMCmd;
-import org.apache.cloudstack.api.command.user.vm.UpgradeVMCmd;
-import org.apache.cloudstack.api.command.user.volume.AttachVolumeCmd;
-import org.apache.cloudstack.api.command.user.volume.DetachVolumeCmd;
-import org.apache.log4j.Logger;
-
 import com.cloud.agent.api.Answer;
 import com.cloud.agent.api.StopAnswer;
 import com.cloud.agent.api.baremetal.IpmISetBootDevCommand;
 import com.cloud.agent.api.baremetal.IpmiBootorResetCommand;
 import com.cloud.agent.manager.Commands;
-import org.apache.cloudstack.api.command.user.vm.StartVMCmd;
 import com.cloud.baremetal.PxeServerManager.PxeServerType;
 import com.cloud.configuration.Resource.ResourceType;
 import com.cloud.configuration.dao.ConfigurationDao;
@@ -47,14 +30,8 @@
 import com.cloud.deploy.DeployDestination;
 import com.cloud.domain.DomainVO;
 import com.cloud.event.EventTypes;
-import com.cloud.event.UsageEventVO;
-import com.cloud.exception.ConcurrentOperationException;
-import com.cloud.exception.InsufficientCapacityException;
-import com.cloud.exception.InvalidParameterValueException;
-import com.cloud.exception.PermissionDeniedException;
-import com.cloud.exception.ResourceAllocationException;
-import com.cloud.exception.ResourceUnavailableException;
-import com.cloud.exception.StorageUnavailableException;
+import com.cloud.event.UsageEventUtils;
+import com.cloud.exception.*;
 import com.cloud.host.Host;
 import com.cloud.host.HostVO;
 import com.cloud.hypervisor.Hypervisor.HypervisorType;
@@ -71,11 +48,7 @@
 import com.cloud.template.TemplateAdapter;
 import com.cloud.template.TemplateAdapter.TemplateAdapterType;
 import com.cloud.template.TemplateProfile;
-import com.cloud.user.Account;
-import com.cloud.user.AccountVO;
-import com.cloud.user.SSHKeyPair;
-import com.cloud.user.User;
-import com.cloud.user.UserContext;
+import com.cloud.user.*;
 import com.cloud.uservm.UserVm;
 import com.cloud.utils.NumbersUtil;
 import com.cloud.utils.Pair;
@@ -88,19 +61,26 @@
 import com.cloud.utils.exception.CloudRuntimeException;
 import com.cloud.utils.fsm.StateListener;
 import com.cloud.utils.net.NetUtils;
-import com.cloud.vm.BareMetalVmService;
-import com.cloud.vm.NicProfile;
-import com.cloud.vm.NicVO;
-import com.cloud.vm.ReservationContext;
-import com.cloud.vm.UserVmManagerImpl;
-import com.cloud.vm.UserVmVO;
-import com.cloud.vm.VirtualMachine;
+import com.cloud.vm.*;
 import com.cloud.vm.VirtualMachine.Event;
 import com.cloud.vm.VirtualMachine.State;
 import com.cloud.vm.VirtualMachine.Type;
-import com.cloud.vm.VirtualMachineName;
-import com.cloud.vm.VirtualMachineProfile;
 import com.cloud.vm.VirtualMachineProfile.Param;
+import org.apache.cloudstack.api.command.user.template.CreateTemplateCmd;
+import org.apache.cloudstack.api.command.user.vm.DeployVMCmd;
+import org.apache.cloudstack.api.command.user.vm.StartVMCmd;
+import org.apache.cloudstack.api.command.user.vm.UpgradeVMCmd;
+import org.apache.cloudstack.api.command.user.volume.AttachVolumeCmd;
+import org.apache.cloudstack.api.command.user.volume.DetachVolumeCmd;
+import org.apache.log4j.Logger;
+
+import javax.ejb.Local;
+import javax.naming.ConfigurationException;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.Executors;
 
 @Local(value={BareMetalVmManager.class, BareMetalVmService.class})
 public class BareMetalVmManagerImpl extends UserVmManagerImpl implements BareMetalVmManager, BareMetalVmService, Manager,
@@ -367,8 +347,9 @@
 			s_logger.debug("Successfully allocated DB entry for " + vm);
 		}
 		UserContext.current().setEventDetails("Vm Id: " + vm.getId());
-		 UsageEventVO usageEvent = new UsageEventVO(EventTypes.EVENT_VM_CREATE, accountId, cmd.getZoneId(), vm.getId(), vm.getHostName(), offering.getId(), template.getId(), HypervisorType.BareMetal.toString());
-		_usageEventDao.persist(usageEvent);
+        UsageEventUtils.publishUsageEvent(EventTypes.EVENT_VM_CREATE, accountId, cmd.getZoneId(), vm.getId(),
+                vm.getHostName(), offering.getId(), template.getId(), HypervisorType.BareMetal.toString(),
+                VirtualMachine.class.getName(), vm.getUuid());
 
 		_resourceLimitMgr.incrementResourceCount(accountId, ResourceType.user_vm);
 
diff --git a/server/src/com/cloud/configuration/DefaultInterceptorLibrary.java b/server/src/com/cloud/configuration/DefaultInterceptorLibrary.java
index ced2618..13a22db 100644
--- a/server/src/com/cloud/configuration/DefaultInterceptorLibrary.java
+++ b/server/src/com/cloud/configuration/DefaultInterceptorLibrary.java
@@ -16,18 +16,18 @@
 // under the License.
 package com.cloud.configuration;
 
-import java.util.List;
-
-import com.cloud.event.ActionEventCallback;
+import com.cloud.event.ActionEventUtils;
 import com.cloud.utils.component.AnnotationInterceptor;
 import com.cloud.utils.component.InterceptorLibrary;
 import com.cloud.utils.db.DatabaseCallback;
 
+import java.util.List;
+
 public class DefaultInterceptorLibrary implements InterceptorLibrary {
 
     @Override
     public void addInterceptors(List<AnnotationInterceptor<?>> interceptors) {
         interceptors.add(new DatabaseCallback());
-        interceptors.add(new ActionEventCallback());
+        interceptors.add(new ActionEventUtils.ActionEventCallback());
     }
 }
diff --git a/server/src/com/cloud/event/ActionEventCallback.java b/server/src/com/cloud/event/ActionEventCallback.java
deleted file mode 100644
index f941400..0000000
--- a/server/src/com/cloud/event/ActionEventCallback.java
+++ /dev/null
@@ -1,135 +0,0 @@
-// 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.
-package com.cloud.event;
-
-import java.lang.reflect.AnnotatedElement;
-import java.lang.reflect.Method;
-
-import net.sf.cglib.proxy.Callback;
-import net.sf.cglib.proxy.MethodInterceptor;
-import net.sf.cglib.proxy.MethodProxy;
-
-import com.cloud.user.UserContext;
-import com.cloud.utils.component.AnnotationInterceptor;
-
-public class ActionEventCallback implements MethodInterceptor, AnnotationInterceptor<EventVO> {
-
-    @Override
-    public Object intercept(Object object, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
-        EventVO event = interceptStart(method);
-        boolean success = true;
-        try {
-            return methodProxy.invokeSuper(object, args);
-        } catch (Exception e){
-            success = false;
-            interceptException(method, event);
-            throw e;
-        } finally {
-            if(success){
-                interceptComplete(method, event);
-            }
-        }
-    }
-
-    @Override
-    public boolean needToIntercept(AnnotatedElement element) {
-        if (!(element instanceof Method)) {
-            return false;
-            
-        }
-        Method method = (Method)element;
-        ActionEvent actionEvent = method.getAnnotation(ActionEvent.class);
-        if (actionEvent != null) {
-            return true;
-        }
-        
-        return false;
-    }
-
-    @Override
-    public EventVO interceptStart(AnnotatedElement element) {
-        EventVO event = null;
-        Method method = (Method)element;
-        ActionEvent actionEvent = method.getAnnotation(ActionEvent.class);
-        if (actionEvent != null) {
-            boolean async = actionEvent.async();
-            if(async){
-                UserContext ctx = UserContext.current();
-                long userId = ctx.getCallerUserId();
-                long accountId = ctx.getAccountId();
-                long startEventId = ctx.getStartEventId();
-                String eventDescription = actionEvent.eventDescription();
-                if(ctx.getEventDetails() != null){
-                    eventDescription += ". "+ctx.getEventDetails();
-                }
-                EventUtils.saveStartedEvent(userId, accountId, actionEvent.eventType(), eventDescription, startEventId);
-            }
-        }
-        return event;
-    }
-
-    @Override
-    public void interceptComplete(AnnotatedElement element, EventVO event) {
-        Method method = (Method)element;
-        ActionEvent actionEvent = method.getAnnotation(ActionEvent.class);
-        if (actionEvent != null) {
-            UserContext ctx = UserContext.current();
-            long userId = ctx.getCallerUserId();
-            long accountId = ctx.getAccountId();
-            long startEventId = ctx.getStartEventId();
-            String eventDescription = actionEvent.eventDescription();
-            if(ctx.getEventDetails() != null){
-                eventDescription += ". "+ctx.getEventDetails();
-            }            
-            if(actionEvent.create()){
-                //This start event has to be used for subsequent events of this action
-                startEventId = EventUtils.saveCreatedEvent(userId, accountId, EventVO.LEVEL_INFO, actionEvent.eventType(), "Successfully created entity for "+eventDescription);
-                ctx.setStartEventId(startEventId);
-            } else {
-                EventUtils.saveEvent(userId, accountId, EventVO.LEVEL_INFO, actionEvent.eventType(), "Successfully completed "+eventDescription, startEventId);
-            }
-        }
-    }
-
-    @Override
-    public void interceptException(AnnotatedElement element, EventVO event) {
-        Method method = (Method)element;
-        ActionEvent actionEvent = method.getAnnotation(ActionEvent.class);
-        if (actionEvent != null) {
-            UserContext ctx = UserContext.current();
-            long userId = ctx.getCallerUserId();
-            long accountId = ctx.getAccountId();
-            long startEventId = ctx.getStartEventId();
-            String eventDescription = actionEvent.eventDescription();
-            if(ctx.getEventDetails() != null){
-                eventDescription += ". "+ctx.getEventDetails();
-            }
-            if(actionEvent.create()){
-                long eventId = EventUtils.saveCreatedEvent(userId, accountId, EventVO.LEVEL_ERROR, actionEvent.eventType(), "Error while creating entity for "+eventDescription);
-                ctx.setStartEventId(eventId);
-            } else {
-                EventUtils.saveEvent(userId, accountId, EventVO.LEVEL_ERROR, actionEvent.eventType(), "Error while "+eventDescription, startEventId);
-            }
-        }
-    }
-
-    @Override
-    public Callback getCallback() {
-        return this;
-    }
-    
-}
diff --git a/server/src/com/cloud/event/ActionEventUtils.java b/server/src/com/cloud/event/ActionEventUtils.java
new file mode 100755
index 0000000..744f46f
--- /dev/null
+++ b/server/src/com/cloud/event/ActionEventUtils.java
@@ -0,0 +1,288 @@
+// 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.
+
+package com.cloud.event;
+
+import com.cloud.event.dao.EventDao;
+import com.cloud.server.ManagementServer;
+import com.cloud.user.Account;
+import com.cloud.user.AccountVO;
+import com.cloud.user.User;
+import com.cloud.user.UserContext;
+import com.cloud.user.dao.AccountDao;
+import com.cloud.user.dao.UserDao;
+import com.cloud.utils.component.Adapters;
+import com.cloud.utils.component.AnnotationInterceptor;
+import com.cloud.utils.component.ComponentLocator;
+import net.sf.cglib.proxy.Callback;
+import net.sf.cglib.proxy.MethodInterceptor;
+import net.sf.cglib.proxy.MethodProxy;
+import org.apache.cloudstack.framework.events.EventBus;
+import org.apache.cloudstack.framework.events.EventBusException;
+import org.apache.log4j.Logger;
+
+import java.lang.reflect.AnnotatedElement;
+import java.lang.reflect.Method;
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.Map;
+
+public class ActionEventUtils {
+
+    private static EventDao _eventDao = ComponentLocator.getLocator(ManagementServer.Name).getDao(EventDao.class);
+    private static AccountDao _accountDao = ComponentLocator.getLocator(ManagementServer.Name).getDao(AccountDao.class);
+    protected static UserDao _userDao = ComponentLocator.getLocator(ManagementServer.Name).getDao(UserDao.class);
+    private static final Logger s_logger = Logger.getLogger(ActionEventUtils.class);
+
+    // get the event bus provider if configured
+    protected static EventBus _eventBus = null;
+
+    static {
+        Adapters<EventBus> eventBusImpls = ComponentLocator.getLocator(ManagementServer.Name).getAdapters(EventBus.class);
+        if (eventBusImpls != null) {
+            Enumeration<EventBus> eventBusenum = eventBusImpls.enumeration();
+            if (eventBusenum != null && eventBusenum.hasMoreElements()) {
+                _eventBus = eventBusenum.nextElement(); // configure event bus if configured
+            }
+        }
+    }
+
+    public static Long onActionEvent(Long userId, Long accountId, Long domainId, String type, String description) {
+
+        publishOnEventBus(userId, accountId, EventCategory.ACTION_EVENT.getName(),
+                type, com.cloud.event.Event.State.Completed);
+
+        Event event = persistActionEvent(userId, accountId, domainId, null, type, Event.State.Completed,
+                description, null);
+
+        return event.getId();
+    }
+
+    /*
+     * Save event after scheduling an async job
+     */
+    public static Long onScheduledActionEvent(Long userId, Long accountId, String type, String description,
+                                              long startEventId) {
+
+        publishOnEventBus(userId, accountId, EventCategory.ACTION_EVENT.getName(), type,
+                com.cloud.event.Event.State.Scheduled);
+
+        Event event = persistActionEvent(userId, accountId, null, null, type, Event.State.Scheduled,
+                description, startEventId);
+
+        return event.getId();
+    }
+
+    /*
+     * Save event after starting execution of an async job
+     */
+    public static Long onStartedActionEvent(Long userId, Long accountId, String type, String description,
+                                            long startEventId) {
+
+        publishOnEventBus(userId, accountId, EventCategory.ACTION_EVENT.getName(), type,
+                com.cloud.event.Event.State.Started);
+
+        Event event = persistActionEvent(userId, accountId, null, null, type, Event.State.Started,
+                description, startEventId);
+        return event.getId();
+    }
+
+    public static Long onCompletedActionEvent(Long userId, Long accountId, String level, String type,
+                                              String description, long startEventId) {
+
+        publishOnEventBus(userId, accountId, EventCategory.ACTION_EVENT.getName(), type,
+                com.cloud.event.Event.State.Completed);
+
+        Event event = persistActionEvent(userId, accountId, null, level, type, Event.State.Completed,
+                description, startEventId);
+
+        return event.getId();
+    }
+
+    public static Long onCreatedActionEvent(Long userId, Long accountId, String level, String type, String description) {
+
+        publishOnEventBus(userId, accountId, EventCategory.ACTION_EVENT.getName(), type,
+                com.cloud.event.Event.State.Created);
+
+        Event event = persistActionEvent(userId, accountId, null, level, type, Event.State.Created, description, null);
+
+        return event.getId();
+    }
+
+    private static Event persistActionEvent(Long userId, Long accountId, Long domainId, String level, String type,
+                                           Event.State state, String description, Long startEventId) {
+        EventVO event = new EventVO();
+        event.setUserId(userId);
+        event.setAccountId(accountId);
+        event.setType(type);
+        event.setState(state);
+        event.setDescription(description);
+        if (domainId != null) {
+            event.setDomainId(domainId);
+        } else {
+            event.setDomainId(getDomainId(accountId));
+        }
+        if (level != null && !level.isEmpty()) {
+            event.setLevel(level);
+        }
+        if (startEventId != null) {
+            event.setStartId(startEventId);
+        }
+        event = _eventDao.persist(event);
+        return event;
+    }
+
+    private static void publishOnEventBus(long userId, long accountId, String eventCategory,
+                                          String eventType, Event.State state) {
+        if (_eventBus == null) {
+            return; // no provider is configured to provide events bus, so just return
+        }
+
+        org.apache.cloudstack.framework.events.Event event = new org.apache.cloudstack.framework.events.Event(
+                ManagementServer.Name,
+                eventCategory,
+                eventType,
+                EventTypes.getEntityForEvent(eventType), null);
+
+        Map<String, String> eventDescription = new HashMap<String, String>();
+        Account account = _accountDao.findById(accountId);
+        User user = _userDao.findById(userId);
+        eventDescription.put("user", user.getUuid());
+        eventDescription.put("account", account.getUuid());
+        eventDescription.put("event", eventType);
+        eventDescription.put("status", state.toString());
+        event.setDescription(eventDescription);
+
+        try {
+            _eventBus.publish(event);
+        } catch (EventBusException e) {
+            s_logger.warn("Failed to publish action event on the the event bus.");
+        }
+    }
+
+    private static long getDomainId(long accountId){
+        AccountVO account = _accountDao.findByIdIncludingRemoved(accountId);
+        return account.getDomainId();
+    }
+
+    public static class ActionEventCallback implements MethodInterceptor, AnnotationInterceptor<EventVO> {
+
+        @Override
+        public Object intercept(Object object, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
+            EventVO event = interceptStart(method);
+            boolean success = true;
+            try {
+                return methodProxy.invokeSuper(object, args);
+            } catch (Exception e){
+                success = false;
+                interceptException(method, event);
+                throw e;
+            } finally {
+                if(success){
+                    interceptComplete(method, event);
+                }
+            }
+        }
+
+        @Override
+        public boolean needToIntercept(AnnotatedElement element) {
+            if (!(element instanceof Method)) {
+                return false;
+
+            }
+            Method method = (Method)element;
+            ActionEvent actionEvent = method.getAnnotation(ActionEvent.class);
+            if (actionEvent != null) {
+                return true;
+            }
+
+            return false;
+        }
+
+        @Override
+        public EventVO interceptStart(AnnotatedElement element) {
+            EventVO event = null;
+            Method method = (Method)element;
+            ActionEvent actionEvent = method.getAnnotation(ActionEvent.class);
+            if (actionEvent != null) {
+                boolean async = actionEvent.async();
+                if(async){
+                    UserContext ctx = UserContext.current();
+                    long userId = ctx.getCallerUserId();
+                    long accountId = ctx.getAccountId();
+                    long startEventId = ctx.getStartEventId();
+                    String eventDescription = actionEvent.eventDescription();
+                    if(ctx.getEventDetails() != null){
+                        eventDescription += ". "+ctx.getEventDetails();
+                    }
+                    ActionEventUtils.onStartedActionEvent(userId, accountId, actionEvent.eventType(), eventDescription, startEventId);
+                }
+            }
+            return event;
+        }
+
+        @Override
+        public void interceptComplete(AnnotatedElement element, EventVO event) {
+            Method method = (Method)element;
+            ActionEvent actionEvent = method.getAnnotation(ActionEvent.class);
+            if (actionEvent != null) {
+                UserContext ctx = UserContext.current();
+                long userId = ctx.getCallerUserId();
+                long accountId = ctx.getAccountId();
+                long startEventId = ctx.getStartEventId();
+                String eventDescription = actionEvent.eventDescription();
+                if(ctx.getEventDetails() != null){
+                    eventDescription += ". "+ctx.getEventDetails();
+                }
+                if(actionEvent.create()){
+                    //This start event has to be used for subsequent events of this action
+                    startEventId = ActionEventUtils.onCreatedActionEvent(userId, accountId, EventVO.LEVEL_INFO, actionEvent.eventType(), "Successfully created entity for " + eventDescription);
+                    ctx.setStartEventId(startEventId);
+                } else {
+                    ActionEventUtils.onCompletedActionEvent(userId, accountId, EventVO.LEVEL_INFO, actionEvent.eventType(), "Successfully completed " + eventDescription, startEventId);
+                }
+            }
+        }
+
+        @Override
+        public void interceptException(AnnotatedElement element, EventVO event) {
+            Method method = (Method)element;
+            ActionEvent actionEvent = method.getAnnotation(ActionEvent.class);
+            if (actionEvent != null) {
+                UserContext ctx = UserContext.current();
+                long userId = ctx.getCallerUserId();
+                long accountId = ctx.getAccountId();
+                long startEventId = ctx.getStartEventId();
+                String eventDescription = actionEvent.eventDescription();
+                if(ctx.getEventDetails() != null){
+                    eventDescription += ". "+ctx.getEventDetails();
+                }
+                if(actionEvent.create()){
+                    long eventId = ActionEventUtils.onCreatedActionEvent(userId, accountId, EventVO.LEVEL_ERROR, actionEvent.eventType(), "Error while creating entity for " + eventDescription);
+                    ctx.setStartEventId(eventId);
+                } else {
+                    ActionEventUtils.onCompletedActionEvent(userId, accountId, EventVO.LEVEL_ERROR, actionEvent.eventType(), "Error while " + eventDescription, startEventId);
+                }
+            }
+        }
+
+        @Override
+        public Callback getCallback() {
+            return this;
+        }
+    }
+}
diff --git a/server/src/com/cloud/event/AlertGenerator.java b/server/src/com/cloud/event/AlertGenerator.java
new file mode 100644
index 0000000..4286377
--- /dev/null
+++ b/server/src/com/cloud/event/AlertGenerator.java
@@ -0,0 +1,87 @@
+// 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.
+
+package com.cloud.event;
+
+import com.cloud.dc.DataCenterVO;
+import com.cloud.dc.HostPodVO;
+import com.cloud.dc.dao.DataCenterDao;
+import com.cloud.dc.dao.HostPodDao;
+import com.cloud.server.ManagementServer;
+import com.cloud.utils.component.Adapters;
+import com.cloud.utils.component.ComponentLocator;
+import org.apache.cloudstack.framework.events.*;
+import org.apache.log4j.Logger;
+
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.Map;
+
+public class AlertGenerator {
+
+    private static final Logger s_logger = Logger.getLogger(AlertGenerator.class);
+    private static DataCenterDao _dcDao =  ComponentLocator.getLocator(ManagementServer.Name).getDao(DataCenterDao.class);
+    private static HostPodDao _podDao = ComponentLocator.getLocator(ManagementServer.Name).getDao(HostPodDao.class);
+
+    // get the event bus provider if configured
+    protected static EventBus _eventBus = null;
+    static {
+        Adapters<EventBus> eventBusImpls = ComponentLocator.getLocator(ManagementServer.Name).getAdapters(EventBus.class);
+        if (eventBusImpls != null) {
+            Enumeration<EventBus> eventBusenum = eventBusImpls.enumeration();
+            if (eventBusenum != null && eventBusenum.hasMoreElements()) {
+                _eventBus = eventBusenum.nextElement(); // configure event bus if configured
+            }
+        }
+    }
+
+    public static void publishAlertOnEventBus(String alertType, long dataCenterId, Long podId, String subject, String body) {
+        if (_eventBus == null) {
+            return; // no provider is configured to provider events bus, so just return
+        }
+
+        org.apache.cloudstack.framework.events.Event event =
+                new org.apache.cloudstack.framework.events.Event(ManagementServer.Name,
+                        EventCategory.ALERT_EVENT.getName(),
+                        alertType,
+                        null,
+                        null);
+
+        Map<String, String> eventDescription = new HashMap<String, String>();
+        DataCenterVO dc = _dcDao.findById(dataCenterId);
+        HostPodVO pod = _podDao.findById(podId);
+
+        eventDescription.put("event", alertType);
+        if (dc != null) {
+            eventDescription.put("dataCenterId", dc.getUuid());
+        } else {
+            eventDescription.put("dataCenterId", null);
+        }
+        if (pod != null) {
+            eventDescription.put("podId", pod.getUuid());
+        } else {
+            eventDescription.put("podId", null);
+        }
+        event.setDescription(eventDescription);
+
+        try {
+            _eventBus.publish(event);
+        } catch (EventBusException e) {
+            s_logger.warn("Failed to publish alert on the the event bus.");
+        }
+    }
+}
diff --git a/server/src/com/cloud/event/EventUtils.java b/server/src/com/cloud/event/EventUtils.java
deleted file mode 100755
index 3672ee7..0000000
--- a/server/src/com/cloud/event/EventUtils.java
+++ /dev/null
@@ -1,102 +0,0 @@
-// 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.
-package com.cloud.event;
-
-import com.cloud.event.dao.EventDao;
-import com.cloud.server.ManagementServer;
-import com.cloud.user.AccountVO;
-import com.cloud.user.dao.AccountDao;
-import com.cloud.utils.component.ComponentLocator;
-
-public class EventUtils {
-	private static EventDao _eventDao = ComponentLocator.getLocator(ManagementServer.Name).getDao(EventDao.class);
-	private static AccountDao _accountDao = ComponentLocator.getLocator(ManagementServer.Name).getDao(AccountDao.class);
-
-    public static Long saveEvent(Long userId, Long accountId, Long domainId, String type, String description) {
-        EventVO event = new EventVO();
-        event.setUserId(userId);
-        event.setAccountId(accountId);
-        event.setDomainId(domainId);
-        event.setType(type);
-        event.setDescription(description);
-        event = _eventDao.persist(event);
-        return event.getId();
-    }
-    
-    /*
-     * Save event after scheduling an async job
-     */
-    public static Long saveScheduledEvent(Long userId, Long accountId, String type, String description, long startEventId) {
-        EventVO event = new EventVO();
-        event.setUserId(userId);
-        event.setAccountId(accountId);
-        event.setDomainId(getDomainId(accountId));
-        event.setType(type);
-        event.setStartId(startEventId);
-        event.setState(Event.State.Scheduled);
-        event.setDescription("Scheduled async job for "+description);
-        event = _eventDao.persist(event);
-        return event.getId();
-    }
-    
-    /*
-     * Save event after starting execution of an async job
-     */
-    public static Long saveStartedEvent(Long userId, Long accountId, String type, String description, long startEventId) {
-        EventVO event = new EventVO();
-        event.setUserId(userId);
-        event.setAccountId(accountId);
-        event.setDomainId(getDomainId(accountId));
-        event.setType(type);
-        event.setState(Event.State.Started);
-        event.setDescription("Starting job for "+description);
-        event.setStartId(startEventId);
-        event = _eventDao.persist(event);
-    	return event.getId();
-    }    
-
-    public static Long saveEvent(Long userId, Long accountId, String level, String type, String description, long startEventId) {
-        EventVO event = new EventVO();
-        event.setUserId(userId);
-        event.setAccountId(accountId);
-        event.setDomainId(getDomainId(accountId));
-        event.setType(type);
-        event.setDescription(description);
-        event.setLevel(level);
-        event.setStartId(startEventId);
-        event = _eventDao.persist(event);
-        return (event != null ? event.getId() : null);
-    }
-    
-    public static Long saveCreatedEvent(Long userId, Long accountId, String level, String type, String description) {
-        EventVO event = new EventVO();
-        event.setUserId(userId);
-        event.setAccountId(accountId);
-        event.setDomainId(getDomainId(accountId));
-        event.setType(type);
-        event.setLevel(level);
-        event.setState(Event.State.Created);
-        event.setDescription(description);
-        event = _eventDao.persist(event);
-        return event.getId();
-    }
-    
-    private static long getDomainId(long accountId){
-    	AccountVO account = _accountDao.findByIdIncludingRemoved(accountId);
-    	return account.getDomainId();
-    }
-}
diff --git a/server/src/com/cloud/event/UsageEventUtils.java b/server/src/com/cloud/event/UsageEventUtils.java
new file mode 100644
index 0000000..904525e
--- /dev/null
+++ b/server/src/com/cloud/event/UsageEventUtils.java
@@ -0,0 +1,119 @@
+package com.cloud.event;
+
+import com.cloud.dc.DataCenterVO;
+import com.cloud.dc.dao.DataCenterDao;
+import com.cloud.event.dao.UsageEventDao;
+import com.cloud.server.ManagementServer;
+import com.cloud.user.Account;
+import com.cloud.user.dao.AccountDao;
+import com.cloud.utils.component.Adapters;
+import com.cloud.utils.component.ComponentLocator;
+import org.apache.cloudstack.framework.events.EventBus;
+import org.apache.cloudstack.framework.events.Event;
+import org.apache.cloudstack.framework.events.EventBusException;
+import org.apache.log4j.Logger;
+
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.Map;
+
+public class UsageEventUtils {
+
+    private static UsageEventDao _usageEventDao = ComponentLocator.getLocator(ManagementServer.Name).getDao(UsageEventDao.class);
+    private static AccountDao _accountDao = ComponentLocator.getLocator(ManagementServer.Name).getDao(AccountDao.class);
+    private static DataCenterDao _dcDao =  ComponentLocator.getLocator(ManagementServer.Name).getDao(DataCenterDao.class);
+    private static final Logger s_logger = Logger.getLogger(UsageEventUtils.class);
+
+    // get the event bus provider if configured
+    protected static EventBus _eventBus = null;
+    static {
+        Adapters<EventBus> eventBusImpls = ComponentLocator.getLocator(ManagementServer.Name).getAdapters(EventBus.class);
+        if (eventBusImpls != null) {
+            Enumeration<EventBus> eventBusenum = eventBusImpls.enumeration();
+            if (eventBusenum != null && eventBusenum.hasMoreElements()) {
+                _eventBus = eventBusenum.nextElement(); // configure event bus if configured
+            }
+        }
+    }
+
+    public static void publishUsageEvent(String usageType, long accountId, long zoneId,
+                                         long resourceId, String resourceName,
+                                         Long offeringId, Long templateId, Long size,
+                                         String entityType, String entityUUID) {
+        saveUsageEvent(usageType, accountId, zoneId, resourceId, resourceName, offeringId, templateId, size);
+        publishUsageEvent(usageType, accountId, zoneId, entityType, entityUUID);
+    }
+
+    public static void publishUsageEvent(String usageType, long accountId, long zoneId, long resourceId,
+                                         String resourceName, String entityType, String entityUUID) {
+        saveUsageEvent(usageType, accountId, zoneId, resourceId, resourceName);
+        publishUsageEvent(usageType, accountId, zoneId, entityType, entityUUID);
+    }
+
+    public static void publishUsageEvent(String usageType, long accountId, long zoneId,
+                                         long ipAddressId, String ipAddress, boolean isSourceNat,
+                                         String guestType, boolean isSystem, String entityType, String entityUUID) {
+        saveUsageEvent(usageType, accountId, zoneId, ipAddressId, ipAddress, isSourceNat, guestType, isSystem);
+        publishUsageEvent(usageType, accountId, zoneId, entityType, entityUUID);
+    }
+
+    public static void publishUsageEvent(String usageType, long accountId, long zoneId, long resourceId,
+                                         String resourceName, Long offeringId, Long templateId, String resourceType,
+                                         String entityType, String entityUUID) {
+        saveUsageEvent(usageType, accountId, zoneId, resourceId, resourceName, offeringId, templateId, resourceType);
+        publishUsageEvent(usageType, accountId, zoneId, entityType, entityUUID);
+    }
+
+    public static void publishUsageEvent(String usageType, long accountId,long zoneId, long vmId,
+                                         long securityGroupId, String entityType, String entityUUID) {
+        saveUsageEvent(usageType, accountId, zoneId, vmId, securityGroupId);
+        publishUsageEvent(usageType, accountId, zoneId, entityType, entityUUID);
+    }
+
+    public static void saveUsageEvent(String usageType, long accountId, long zoneId, long resourceId, String resourceName, Long offeringId, Long templateId, Long size) {
+        _usageEventDao.persist( new UsageEventVO(usageType, accountId, zoneId, resourceId, resourceName, offeringId, templateId, size));
+    }
+
+    public static void saveUsageEvent(String usageType, long accountId, long zoneId, long resourceId, String resourceName) {
+        _usageEventDao.persist( new UsageEventVO(usageType, accountId, zoneId, resourceId, resourceName));
+    }
+
+    public static void saveUsageEvent(String usageType, long accountId, long zoneId, long ipAddressId, String ipAddress, boolean isSourceNat, String guestType, boolean isSystem) {
+        _usageEventDao.persist( new UsageEventVO(usageType, accountId, zoneId, ipAddressId, ipAddress, isSourceNat, guestType, isSystem));
+    }
+
+    public static void saveUsageEvent(String usageType, long accountId, long zoneId, long resourceId, String resourceName, Long offeringId, Long templateId, String resourceType) {
+        _usageEventDao.persist( new UsageEventVO(usageType, accountId, zoneId, resourceId, resourceName, offeringId, templateId, resourceType));
+    }
+
+    public static void saveUsageEvent(String usageType, long accountId,long zoneId, long vmId, long securityGroupId) {
+        _usageEventDao.persist( new UsageEventVO( usageType, accountId, zoneId, vmId, securityGroupId));
+    }
+
+    private static void publishUsageEvent(String usageEventType, Long accountId, Long zoneId, String resourceType, String resourceUUID) {
+
+        if (_eventBus == null) {
+            return; // no provider is configured to provider events bus, so just return
+        }
+
+        Account account = _accountDao.findById(accountId);
+        DataCenterVO dc = _dcDao.findById(zoneId);
+
+        Event event = new Event(ManagementServer.Name, EventCategory.USAGE_EVENT.getName(), usageEventType,
+                resourceType, resourceUUID);
+
+        Map<String, String> eventDescription = new HashMap<String, String>();
+        eventDescription.put("account", account.getUuid());
+        eventDescription.put("zone", dc.getUuid());
+        eventDescription.put("event", usageEventType);
+        eventDescription.put("resource", resourceType);
+        eventDescription.put("id", resourceUUID);
+        event.setDescription(eventDescription);
+
+        try {
+            _eventBus.publish(event);
+        } catch (EventBusException e) {
+            s_logger.warn("Failed to publish usage event on the the event bus.");
+        }
+    }
+}
diff --git a/server/src/com/cloud/network/NetworkManagerImpl.java b/server/src/com/cloud/network/NetworkManagerImpl.java
index 0a4851f..3d83487 100755
--- a/server/src/com/cloud/network/NetworkManagerImpl.java
+++ b/server/src/com/cloud/network/NetworkManagerImpl.java
@@ -16,39 +16,9 @@
 // under the License.
 package com.cloud.network;
 
-import java.net.URI;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.Comparator;
-import java.util.Date;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Map;
-import java.util.Random;
-import java.util.Set;
-import java.util.concurrent.Executors;
-import java.util.concurrent.ScheduledExecutorService;
-import java.util.concurrent.TimeUnit;
-
-import javax.ejb.Local;
-import javax.naming.ConfigurationException;
-
-import org.apache.cloudstack.acl.ControlledEntity.ACLType;
-import org.apache.cloudstack.acl.SecurityChecker.AccessType;
-import org.apache.log4j.Logger;
-
 import com.cloud.agent.AgentManager;
 import com.cloud.agent.Listener;
-import com.cloud.agent.api.AgentControlAnswer;
-import com.cloud.agent.api.AgentControlCommand;
-import com.cloud.agent.api.Answer;
-import com.cloud.agent.api.CheckNetworkAnswer;
-import com.cloud.agent.api.CheckNetworkCommand;
-import com.cloud.agent.api.Command;
-import com.cloud.agent.api.StartupCommand;
-import com.cloud.agent.api.StartupRoutingCommand;
+import com.cloud.agent.api.*;
 import com.cloud.agent.api.to.NicTO;
 import com.cloud.alert.AlertManager;
 import com.cloud.api.ApiDBUtils;
@@ -56,15 +26,9 @@
 import com.cloud.configuration.ConfigurationManager;
 import com.cloud.configuration.Resource.ResourceType;
 import com.cloud.configuration.dao.ConfigurationDao;
-import com.cloud.dc.AccountVlanMapVO;
-import com.cloud.dc.DataCenter;
+import com.cloud.dc.*;
 import com.cloud.dc.DataCenter.NetworkType;
-import com.cloud.dc.DataCenterVO;
-import com.cloud.dc.Pod;
-import com.cloud.dc.PodVlanMapVO;
-import com.cloud.dc.Vlan;
 import com.cloud.dc.Vlan.VlanType;
-import com.cloud.dc.VlanVO;
 import com.cloud.dc.dao.AccountVlanMapDao;
 import com.cloud.dc.dao.DataCenterDao;
 import com.cloud.dc.dao.PodVlanMapDao;
@@ -75,63 +39,30 @@
 import com.cloud.domain.Domain;
 import com.cloud.domain.dao.DomainDao;
 import com.cloud.event.EventTypes;
-import com.cloud.event.UsageEventVO;
+import com.cloud.event.UsageEventUtils;
 import com.cloud.event.dao.UsageEventDao;
-import com.cloud.exception.AccountLimitException;
-import com.cloud.exception.ConcurrentOperationException;
-import com.cloud.exception.ConnectionException;
-import com.cloud.exception.InsufficientAddressCapacityException;
-import com.cloud.exception.InsufficientCapacityException;
-import com.cloud.exception.InsufficientVirtualNetworkCapcityException;
-import com.cloud.exception.InvalidParameterValueException;
-import com.cloud.exception.PermissionDeniedException;
-import com.cloud.exception.ResourceAllocationException;
-import com.cloud.exception.ResourceUnavailableException;
-import com.cloud.exception.UnsupportedServiceException;
+import com.cloud.exception.*;
 import com.cloud.host.Host;
 import com.cloud.host.HostVO;
 import com.cloud.host.Status;
 import com.cloud.host.dao.HostDao;
 import com.cloud.hypervisor.Hypervisor.HypervisorType;
 import com.cloud.network.IpAddress.State;
-import com.cloud.network.Network.Capability;
-import com.cloud.network.Network.GuestType;
-import com.cloud.network.Network.Provider;
-import com.cloud.network.Network.Service;
+import com.cloud.network.Network.*;
 import com.cloud.network.Networks.AddressFormat;
 import com.cloud.network.Networks.BroadcastDomainType;
 import com.cloud.network.Networks.IsolationType;
 import com.cloud.network.Networks.TrafficType;
 import com.cloud.network.addr.PublicIp;
-import com.cloud.network.dao.FirewallRulesDao;
-import com.cloud.network.dao.IPAddressDao;
-import com.cloud.network.dao.LoadBalancerDao;
-import com.cloud.network.dao.NetworkDao;
-import com.cloud.network.dao.NetworkServiceMapDao;
-import com.cloud.network.dao.PhysicalNetworkDao;
-import com.cloud.network.dao.PhysicalNetworkServiceProviderDao;
-import com.cloud.network.dao.PhysicalNetworkTrafficTypeDao;
-import com.cloud.network.dao.PhysicalNetworkTrafficTypeVO;
-import com.cloud.network.element.DhcpServiceProvider;
-import com.cloud.network.element.IpDeployer;
-import com.cloud.network.element.LoadBalancingServiceProvider;
-import com.cloud.network.element.NetworkElement;
-import com.cloud.network.element.StaticNatServiceProvider;
-import com.cloud.network.element.UserDataServiceProvider;
+import com.cloud.network.dao.*;
+import com.cloud.network.element.*;
 import com.cloud.network.guru.NetworkGuru;
 import com.cloud.network.lb.LoadBalancingRule;
 import com.cloud.network.lb.LoadBalancingRule.LbDestination;
 import com.cloud.network.lb.LoadBalancingRule.LbStickinessPolicy;
 import com.cloud.network.lb.LoadBalancingRulesManager;
-import com.cloud.network.rules.FirewallManager;
-import com.cloud.network.rules.FirewallRule;
+import com.cloud.network.rules.*;
 import com.cloud.network.rules.FirewallRule.Purpose;
-import com.cloud.network.rules.FirewallRuleVO;
-import com.cloud.network.rules.PortForwardingRuleVO;
-import com.cloud.network.rules.RulesManager;
-import com.cloud.network.rules.StaticNat;
-import com.cloud.network.rules.StaticNatRule;
-import com.cloud.network.rules.StaticNatRuleImpl;
 import com.cloud.network.rules.dao.PortForwardingRulesDao;
 import com.cloud.network.vpc.NetworkACLManager;
 import com.cloud.network.vpc.VpcManager;
@@ -144,11 +75,7 @@
 import com.cloud.offerings.dao.NetworkOfferingDao;
 import com.cloud.offerings.dao.NetworkOfferingServiceMapDao;
 import com.cloud.org.Grouping;
-import com.cloud.user.Account;
-import com.cloud.user.AccountManager;
-import com.cloud.user.ResourceLimitService;
-import com.cloud.user.User;
-import com.cloud.user.UserContext;
+import com.cloud.user.*;
 import com.cloud.user.dao.AccountDao;
 import com.cloud.utils.NumbersUtil;
 import com.cloud.utils.Pair;
@@ -156,30 +83,30 @@
 import com.cloud.utils.component.Inject;
 import com.cloud.utils.component.Manager;
 import com.cloud.utils.concurrency.NamedThreadFactory;
-import com.cloud.utils.db.DB;
-import com.cloud.utils.db.Filter;
+import com.cloud.utils.db.*;
 import com.cloud.utils.db.JoinBuilder.JoinType;
-import com.cloud.utils.db.SearchBuilder;
-import com.cloud.utils.db.SearchCriteria;
 import com.cloud.utils.db.SearchCriteria.Op;
-import com.cloud.utils.db.Transaction;
 import com.cloud.utils.exception.CloudRuntimeException;
+import com.cloud.utils.fsm.NoTransitionException;
+import com.cloud.utils.fsm.StateMachine2;
 import com.cloud.utils.net.Ip;
 import com.cloud.utils.net.NetUtils;
-import com.cloud.vm.Nic;
-import com.cloud.vm.NicProfile;
-import com.cloud.vm.NicVO;
-import com.cloud.vm.ReservationContext;
-import com.cloud.vm.ReservationContextImpl;
-import com.cloud.vm.UserVmVO;
-import com.cloud.vm.VMInstanceVO;
-import com.cloud.vm.VirtualMachine;
+import com.cloud.vm.*;
 import com.cloud.vm.VirtualMachine.Type;
-import com.cloud.vm.VirtualMachineProfile;
-import com.cloud.vm.VirtualMachineProfileImpl;
 import com.cloud.vm.dao.NicDao;
 import com.cloud.vm.dao.UserVmDao;
 import com.cloud.vm.dao.VMInstanceDao;
+import org.apache.cloudstack.acl.ControlledEntity.ACLType;
+import org.apache.cloudstack.acl.SecurityChecker.AccessType;
+import org.apache.log4j.Logger;
+
+import javax.ejb.Local;
+import javax.naming.ConfigurationException;
+import java.net.URI;
+import java.util.*;
+import java.util.concurrent.Executors;
+import java.util.concurrent.ScheduledExecutorService;
+import java.util.concurrent.TimeUnit;
 
 /**
  * NetworkManagerImpl implements NetworkManager.
@@ -222,8 +149,6 @@
     @Inject
     LoadBalancingRulesManager _lbMgr;
     @Inject
-    UsageEventDao _usageEventDao;
-    @Inject
     RemoteAccessVpnService _vpnMgr;
     @Inject
     PodVlanMapDao _podVlanMapDao;
@@ -272,8 +197,14 @@
     @Inject
     NetworkACLManager _networkACLMgr;
     @Inject
+    UsageEventDao _usageEventDao;
+    @Inject
     NetworkModel _networkModel;
 
+    protected StateMachine2<Network.State, Network.Event, Network> _stateMachine;
+    private final HashMap<String, NetworkOfferingVO> _systemNetworks = new HashMap<String, NetworkOfferingVO>(5);
+    private static Long _privateOfferingId = null;
+
     ScheduledExecutorService _executor;
 
     SearchBuilder<IPAddressVO> AssignIpAddressSearch;
@@ -405,11 +336,9 @@
             VlanVO vlan = _vlanDao.findById(addr.getVlanId());
 
             String guestType = vlan.getVlanType().toString();
-
-            UsageEventVO usageEvent = new UsageEventVO(EventTypes.EVENT_NET_IP_ASSIGN, owner.getId(),
+            UsageEventUtils.publishUsageEvent(EventTypes.EVENT_NET_IP_ASSIGN, owner.getId(),
                     addr.getDataCenterId(), addr.getId(), addr.getAddress().toString(), addr.isSourceNat(), guestType,
-                    addr.getSystem());
-            _usageEventDao.persist(usageEvent);
+                    addr.getSystem(), addr.getClass().getName(), addr.getUuid());
             // don't increment resource count for direct ip addresses
             if (addr.getAssociatedWithNetworkId() != null) {
                 _resourceLimitMgr.incrementResourceCount(owner.getId(), ResourceType.public_ip);
@@ -1046,6 +975,8 @@
 
         _agentMgr.registerForHostEvents(this, true, false, true);
 
+        Network.State.getStateMachine().registerListener(new NetworkStateListener(_usageEventDao, _networksDao));
+
         s_logger.info("Network Manager is configured.");
 
         return true;
@@ -1069,6 +1000,7 @@
     }
 
     protected NetworkManagerImpl() {
+        setStateMachine();
     }
 
     @Override
@@ -1425,9 +1357,7 @@
             NetworkOfferingVO offering = _networkOfferingDao.findById(network.getNetworkOfferingId());
 
             network.setReservationId(context.getReservationId());
-            network.setState(Network.State.Implementing);
-
-            _networksDao.update(networkId, network);
+            stateTransitTo(network, Event.ImplementNetwork);
 
             Network result = guru.implement(network, offering, dest, context);
             network.setCidr(result.getCidr());
@@ -1440,16 +1370,23 @@
             // implement network elements and re-apply all the network rules
             implementNetworkElementsAndResources(dest, context, network, offering);
 
-            network.setState(Network.State.Implemented);
+            stateTransitTo(network,Event.OperationSucceeded);
+
             network.setRestartRequired(false);
             _networksDao.update(network.getId(), network);
             implemented.set(guru, network);
             return implemented;
+        } catch (NoTransitionException e) {
+            s_logger.error(e.getMessage());
+            return null;
         } finally {
             if (implemented.first() == null) {
                 s_logger.debug("Cleaning up because we're unable to implement the network " + network);
-                network.setState(Network.State.Shutdown);
-                _networksDao.update(networkId, network);
+                try {
+                    stateTransitTo(network,Event.OperationFailed);
+                } catch (NoTransitionException e) {
+                    s_logger.error(e.getMessage());
+                }
 
                 shutdownNetwork(networkId, context, false);
             }
@@ -2045,9 +1982,12 @@
             s_logger.debug("Network is not implemented: " + network);
             return false;
         }
-
-        network.setState(Network.State.Shutdown);
-        _networksDao.update(network.getId(), network);
+        try {
+            stateTransitTo(network, Event.DestroyNetwork);
+        } catch (NoTransitionException e) {
+            network.setState(Network.State.Shutdown);
+            _networksDao.update(network.getId(), network);
+        }
 
         boolean success = shutdownNetworkElementsAndResources(context, cleanupElements, network);
 
@@ -2062,15 +2002,22 @@
             guru.shutdown(profile, _networkOfferingDao.findById(network.getNetworkOfferingId()));
 
             applyProfileToNetwork(network, profile);
-
-            network.setState(Network.State.Allocated);
-            network.setRestartRequired(false);
+            try {
+                stateTransitTo(network, Event.OperationSucceeded);
+            } catch (NoTransitionException e) {
+                network.setState(Network.State.Allocated);
+                network.setRestartRequired(false);
+            }
             _networksDao.update(network.getId(), network);
             _networksDao.clearCheckForGc(networkId);
             result = true;
         } else {
-            network.setState(Network.State.Implemented);
-            _networksDao.update(network.getId(), network);
+            try {
+                stateTransitTo(network, Event.OperationFailed);
+            } catch (NoTransitionException e) {
+                network.setState(Network.State.Implemented);
+                _networksDao.update(network.getId(), network);
+            }
             result = false;
         }
         txn.commit();
@@ -2230,8 +2177,11 @@
                 s_logger.warn("Failed to delete network " + network + "; was unable to cleanup corresponding ip ranges");
             } else {
                 // commit transaction only when ips and vlans for the network are released successfully
-                network.setState(Network.State.Destroy);
-                _networksDao.update(network.getId(), network);
+                try {
+                    stateTransitTo(network, Event.DestroyNetwork);
+                 } catch (NoTransitionException e) {
+                     s_logger.debug(e.getMessage());
+                 }
                 _networksDao.remove(network.getId());
 
                 NetworkOffering ntwkOff = _configMgr.getNetworkOffering(network.getNetworkOfferingId());
@@ -2737,10 +2687,9 @@
 
                 String guestType = vlan.getVlanType().toString();
 
-                UsageEventVO usageEvent = new UsageEventVO(EventTypes.EVENT_NET_IP_RELEASE,
+                UsageEventUtils.publishUsageEvent(EventTypes.EVENT_NET_IP_RELEASE,
                         ip.getAllocatedToAccountId(), ip.getDataCenterId(), addrId, ip.getAddress().addr(),
-                        ip.isSourceNat(), guestType, ip.getSystem());
-                _usageEventDao.persist(usageEvent);
+                        ip.isSourceNat(), guestType, ip.getSystem(), ip.getClass().getName(), ip.getUuid());
             }
 
             ip = _ipAddressDao.markAsUnavailable(addrId);
@@ -3458,6 +3407,15 @@
         return _networkLockTimeout;
     }
 
+
+    protected boolean stateTransitTo(NetworkVO network, Network.Event e) throws NoTransitionException {
+        return _stateMachine.transitTo(network, e, null, _networksDao);
+    }
+
+    private void setStateMachine() {
+        _stateMachine = Network.State.getStateMachine();
+    }
+
     private Map<Service, Set<Provider>> getServiceProvidersMap(long networkId) {
         Map<Service, Set<Provider>> map = new HashMap<Service, Set<Provider>>();
         List<NetworkServiceMapVO> nsms = _ntwkSrvcDao.getServicesInNetwork(networkId);
@@ -3471,7 +3429,7 @@
         }
         return map;
     }
-    
+
     @Override
     public List<Provider> getProvidersForServiceInNetwork(Network network, Service service) {
         Map<Service, Set<Provider>> service2ProviderMap = getServiceProvidersMap(network.getId());
diff --git a/server/src/com/cloud/network/NetworkServiceImpl.java b/server/src/com/cloud/network/NetworkServiceImpl.java
index 7530e94..bcd3f35 100755
--- a/server/src/com/cloud/network/NetworkServiceImpl.java
+++ b/server/src/com/cloud/network/NetworkServiceImpl.java
@@ -16,31 +16,6 @@
 // under the License.
 package com.cloud.network;
 
-import java.security.InvalidParameterException;
-import java.sql.PreparedStatement;
-import java.sql.ResultSet;
-import java.sql.SQLException;
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-import java.util.TreeSet;
-
-import javax.ejb.Local;
-import javax.naming.ConfigurationException;
-
-import org.apache.log4j.Logger;
-
-import org.apache.cloudstack.acl.ControlledEntity.ACLType;
-import org.apache.cloudstack.acl.SecurityChecker.AccessType;
-import org.apache.cloudstack.api.command.admin.usage.ListTrafficTypeImplementorsCmd;
-import org.apache.cloudstack.api.command.user.network.CreateNetworkCmd;
-import org.apache.cloudstack.api.command.user.network.ListNetworksCmd;
-import org.apache.cloudstack.api.command.user.network.RestartNetworkCmd;
-
 import com.cloud.configuration.Config;
 import com.cloud.configuration.ConfigurationManager;
 import com.cloud.configuration.dao.ConfigurationDao;
@@ -58,17 +33,10 @@
 import com.cloud.domain.dao.DomainDao;
 import com.cloud.event.ActionEvent;
 import com.cloud.event.EventTypes;
-import com.cloud.event.UsageEventVO;
+import com.cloud.event.UsageEventUtils;
 import com.cloud.event.dao.EventDao;
 import com.cloud.event.dao.UsageEventDao;
-import com.cloud.exception.ConcurrentOperationException;
-import com.cloud.exception.InsufficientAddressCapacityException;
-import com.cloud.exception.InsufficientCapacityException;
-import com.cloud.exception.InvalidParameterValueException;
-import com.cloud.exception.PermissionDeniedException;
-import com.cloud.exception.ResourceAllocationException;
-import com.cloud.exception.ResourceUnavailableException;
-import com.cloud.exception.UnsupportedServiceException;
+import com.cloud.exception.*;
 import com.cloud.network.IpAddress.State;
 import com.cloud.network.Network.Capability;
 import com.cloud.network.Network.GuestType;
@@ -79,16 +47,7 @@
 import com.cloud.network.PhysicalNetwork.BroadcastDomainRange;
 import com.cloud.network.VirtualRouterProvider.VirtualRouterProviderType;
 import com.cloud.network.addr.PublicIp;
-import com.cloud.network.dao.FirewallRulesDao;
-import com.cloud.network.dao.IPAddressDao;
-import com.cloud.network.dao.NetworkDao;
-import com.cloud.network.dao.NetworkDomainDao;
-import com.cloud.network.dao.NetworkServiceMapDao;
-import com.cloud.network.dao.PhysicalNetworkDao;
-import com.cloud.network.dao.PhysicalNetworkServiceProviderDao;
-import com.cloud.network.dao.PhysicalNetworkServiceProviderVO;
-import com.cloud.network.dao.PhysicalNetworkTrafficTypeDao;
-import com.cloud.network.dao.PhysicalNetworkTrafficTypeVO;
+import com.cloud.network.dao.*;
 import com.cloud.network.element.NetworkElement;
 import com.cloud.network.element.VirtualRouterElement;
 import com.cloud.network.element.VpcVirtualRouterElement;
@@ -109,13 +68,7 @@
 import com.cloud.server.ResourceTag.TaggedResourceType;
 import com.cloud.tags.ResourceTagVO;
 import com.cloud.tags.dao.ResourceTagDao;
-import com.cloud.user.Account;
-import com.cloud.user.AccountManager;
-import com.cloud.user.AccountVO;
-import com.cloud.user.DomainManager;
-import com.cloud.user.ResourceLimitService;
-import com.cloud.user.User;
-import com.cloud.user.UserContext;
+import com.cloud.user.*;
 import com.cloud.user.dao.AccountDao;
 import com.cloud.utils.AnnotationHelper;
 import com.cloud.utils.NumbersUtil;
@@ -123,25 +76,28 @@
 import com.cloud.utils.component.Adapters;
 import com.cloud.utils.component.Inject;
 import com.cloud.utils.component.Manager;
-import com.cloud.utils.db.DB;
-import com.cloud.utils.db.Filter;
-import com.cloud.utils.db.JoinBuilder;
-import com.cloud.utils.db.SearchBuilder;
-import com.cloud.utils.db.SearchCriteria;
+import com.cloud.utils.db.*;
 import com.cloud.utils.db.SearchCriteria.Op;
-import com.cloud.utils.db.Transaction;
 import com.cloud.utils.exception.CloudRuntimeException;
 import com.cloud.utils.net.NetUtils;
-import com.cloud.vm.NicVO;
-import com.cloud.vm.ReservationContext;
-import com.cloud.vm.ReservationContextImpl;
-import com.cloud.vm.SecondaryStorageVmVO;
-import com.cloud.vm.UserVmVO;
-import com.cloud.vm.VMInstanceVO;
-import com.cloud.vm.VirtualMachine;
+import com.cloud.vm.*;
 import com.cloud.vm.dao.NicDao;
 import com.cloud.vm.dao.UserVmDao;
 import com.cloud.vm.dao.VMInstanceDao;
+import org.apache.cloudstack.acl.ControlledEntity.ACLType;
+import org.apache.cloudstack.api.command.admin.usage.ListTrafficTypeImplementorsCmd;
+import org.apache.cloudstack.api.command.user.network.CreateNetworkCmd;
+import org.apache.cloudstack.api.command.user.network.ListNetworksCmd;
+import org.apache.cloudstack.api.command.user.network.RestartNetworkCmd;
+import org.apache.log4j.Logger;
+
+import javax.ejb.Local;
+import javax.naming.ConfigurationException;
+import java.security.InvalidParameterException;
+import java.sql.PreparedStatement;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.util.*;
 
 /**
  * NetworkServiceImpl implements NetworkService.
@@ -1623,10 +1579,8 @@
                         continue;
                     }
                     long isDefault = (nic.isDefaultNic()) ? 1 : 0;
-                    UsageEventVO usageEvent = new UsageEventVO(EventTypes.EVENT_NETWORK_OFFERING_REMOVE, vm.getAccountId(), vm.getDataCenterIdToDeployIn(), vm.getId(), null, oldNetworkOfferingId, null, 0L);
-                    _usageEventDao.persist(usageEvent);
-                    usageEvent = new UsageEventVO(EventTypes.EVENT_NETWORK_OFFERING_ASSIGN, vm.getAccountId(), vm.getDataCenterIdToDeployIn(), vm.getId(), vm.getHostName(), networkOfferingId, null, isDefault);
-                    _usageEventDao.persist(usageEvent);
+                    UsageEventUtils.saveUsageEvent(EventTypes.EVENT_NETWORK_OFFERING_REMOVE, vm.getAccountId(), vm.getDataCenterIdToDeployIn(), vm.getId(), null, oldNetworkOfferingId, null, 0L);
+                    UsageEventUtils.saveUsageEvent(EventTypes.EVENT_NETWORK_OFFERING_ASSIGN, vm.getAccountId(), vm.getDataCenterIdToDeployIn(), vm.getId(), vm.getHostName(), networkOfferingId, null, isDefault);
                 }
                 txn.commit();
             } else {
diff --git a/server/src/com/cloud/network/NetworkStateListener.java b/server/src/com/cloud/network/NetworkStateListener.java
new file mode 100644
index 0000000..1300633
--- /dev/null
+++ b/server/src/com/cloud/network/NetworkStateListener.java
@@ -0,0 +1,90 @@
+package com.cloud.network;
+
+import com.cloud.event.EventCategory;
+import com.cloud.event.dao.UsageEventDao;
+import com.cloud.network.Network.Event;
+import com.cloud.network.Network.State;
+import com.cloud.network.dao.NetworkDao;
+import com.cloud.server.ManagementServer;
+import com.cloud.utils.component.Adapters;
+import com.cloud.utils.component.ComponentLocator;
+import com.cloud.utils.fsm.StateListener;
+import org.apache.cloudstack.framework.events.EventBus;
+import org.apache.cloudstack.framework.events.EventBusException;
+import org.apache.log4j.Logger;
+
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.Map;
+
+public class NetworkStateListener implements StateListener<State, Event, Network> {
+
+    protected UsageEventDao _usageEventDao;
+    protected NetworkDao _networkDao;
+
+    // get the event bus provider if configured
+    protected static EventBus _eventBus = null;
+    static {
+        Adapters<EventBus> eventBusImpls = ComponentLocator.getLocator(ManagementServer.Name).getAdapters(EventBus.class);
+        if (eventBusImpls != null) {
+            Enumeration<EventBus> eventBusenum = eventBusImpls.enumeration();
+            if (eventBusenum != null && eventBusenum.hasMoreElements()) {
+                _eventBus = eventBusenum.nextElement(); // configure event bus if configured
+            }
+        }
+    }
+
+    private static final Logger s_logger = Logger.getLogger(NetworkStateListener.class);
+
+    public NetworkStateListener(UsageEventDao usageEventDao, NetworkDao networkDao) {
+        this._usageEventDao = usageEventDao;
+        this._networkDao = networkDao;
+    }
+
+    @Override
+    public boolean preStateTransitionEvent(State oldState, Event event, State newState, Network vo, boolean status, Object opaque) {
+        pubishOnEventBus(event.name(), "preStateTransitionEvent", vo, oldState, newState);
+        return true;
+    }
+
+    @Override
+    public boolean postStateTransitionEvent(State oldState, Event event, State newState, Network vo, boolean status, Object opaque) {
+        pubishOnEventBus(event.name(), "postStateTransitionEvent", vo, oldState, newState);
+        return true;
+    }
+
+    private void pubishOnEventBus(String event, String status, Network vo, State oldState, State newState) {
+
+        if (_eventBus == null) {
+            return; // no provider is configured to provide events bus, so just return
+        }
+
+        String resourceName = getEntityFromClassName(Network.class.getName());
+        org.apache.cloudstack.framework.events.Event eventMsg =  new org.apache.cloudstack.framework.events.Event(
+                ManagementServer.Name,
+                EventCategory.RESOURCE_STATE_CHANGE_EVENT.getName(),
+                event,
+                resourceName,
+                vo.getUuid());
+        Map<String, String> eventDescription = new HashMap<String, String>();
+        eventDescription.put("resource", resourceName);
+        eventDescription.put("id", vo.getUuid());
+        eventDescription.put("old-state", oldState.name());
+        eventDescription.put("new-state", newState.name());
+        eventMsg.setDescription(eventDescription);
+        try {
+            _eventBus.publish(eventMsg);
+        } catch (EventBusException e) {
+            s_logger.warn("Failed to publish state change event on the the event bus.");
+        }
+    }
+
+    private String getEntityFromClassName(String entityClassName) {
+        int index = entityClassName.lastIndexOf(".");
+        String entityName = entityClassName;
+        if (index != -1) {
+            entityName = entityClassName.substring(index+1);
+        }
+        return entityName;
+    }
+}
diff --git a/server/src/com/cloud/network/NetworkVO.java b/server/src/com/cloud/network/NetworkVO.java
index 14b643b..d0209d7 100644
--- a/server/src/com/cloud/network/NetworkVO.java
+++ b/server/src/com/cloud/network/NetworkVO.java
@@ -246,6 +246,7 @@
         return state;
     }
 
+    // don't use this directly when possible, use Network state machine instead
     public void setState(State state) {
         this.state = state;
     }
diff --git a/server/src/com/cloud/network/dao/NetworkDao.java b/server/src/com/cloud/network/dao/NetworkDao.java
index 1fefb75..18dcb6f 100644
--- a/server/src/com/cloud/network/dao/NetworkDao.java
+++ b/server/src/com/cloud/network/dao/NetworkDao.java
@@ -24,10 +24,12 @@
 import com.cloud.network.NetworkAccountVO;
 import com.cloud.network.NetworkVO;
 import com.cloud.network.Networks.TrafficType;
+import com.cloud.network.Network.State;
 import com.cloud.utils.db.GenericDao;
 import com.cloud.utils.db.SearchBuilder;
+import com.cloud.utils.fsm.StateDao;
 
-public interface NetworkDao extends GenericDao<NetworkVO, Long> {
+public interface NetworkDao extends GenericDao<NetworkVO, Long> , StateDao<State, Network.Event, Network> {
 
     List<NetworkVO> listByOwner(long ownerId);
 
diff --git a/server/src/com/cloud/network/dao/NetworkDaoImpl.java b/server/src/com/cloud/network/dao/NetworkDaoImpl.java
index 29e2f81..2c5b46d 100644
--- a/server/src/com/cloud/network/dao/NetworkDaoImpl.java
+++ b/server/src/com/cloud/network/dao/NetworkDaoImpl.java
@@ -28,6 +28,8 @@
 import com.cloud.network.Network.GuestType;
 import com.cloud.network.Network.Provider;
 import com.cloud.network.Network.Service;
+import com.cloud.network.Network.State;
+import com.cloud.network.Network.Event;
 import com.cloud.network.NetworkAccountDaoImpl;
 import com.cloud.network.NetworkAccountVO;
 import com.cloud.network.NetworkDomainVO;
@@ -42,19 +44,18 @@
 import com.cloud.server.ResourceTag.TaggedResourceType;
 import com.cloud.tags.dao.ResourceTagsDaoImpl;
 import com.cloud.utils.component.ComponentLocator;
-import com.cloud.utils.db.DB;
-import com.cloud.utils.db.GenericDaoBase;
-import com.cloud.utils.db.GenericSearchBuilder;
-import com.cloud.utils.db.JoinBuilder;
+import com.cloud.utils.db.*;
 import com.cloud.utils.db.JoinBuilder.JoinType;
-import com.cloud.utils.db.SearchBuilder;
-import com.cloud.utils.db.SearchCriteria;
 import com.cloud.utils.db.SearchCriteria.Func;
 import com.cloud.utils.db.SearchCriteria.Op;
-import com.cloud.utils.db.SequenceFetcher;
-import com.cloud.utils.db.Transaction;
 import com.cloud.utils.net.NetUtils;
 
+import javax.ejb.Local;
+import javax.persistence.TableGenerator;
+import java.util.List;
+import java.util.Map;
+import java.util.Random;
+
 @Local(value = NetworkDao.class)
 @DB(txn = false)
 public class NetworkDaoImpl extends GenericDaoBase<NetworkVO, Long> implements NetworkDao {
@@ -565,6 +566,20 @@
     }
 
     @Override
+    public boolean updateState(State currentState, Event event, State nextState, Network vo, Object data) {
+       // TODO: ensure this update is correct
+       Transaction txn = Transaction.currentTxn();
+       txn.start();
+
+       NetworkVO networkVo = (NetworkVO) vo;
+       networkVo.setState(nextState);
+       super.update(networkVo.getId(), networkVo);
+
+       txn.commit();
+       return true;
+    }
+
+    @Override
     public List<NetworkVO> listNetworksByAccount(long accountId, long zoneId, Network.GuestType type, boolean isSystem) {
         SearchCriteria<NetworkVO> sc = OfferingAccountNetworkSearch.create();
         sc.setJoinParameters("ntwkOfferingSearch", "isSystem", isSystem);
@@ -580,7 +595,6 @@
     public List<NetworkVO> listRedundantNetworks() {
         SearchCriteria<NetworkVO> sc = AllFieldsSearch.create();
         sc.setJoinParameters("offerings", "isRedundant", true);
-        
         return listBy(sc, null);
     }
 }
diff --git a/server/src/com/cloud/network/firewall/FirewallManagerImpl.java b/server/src/com/cloud/network/firewall/FirewallManagerImpl.java
index d4958f3..a3f60cb 100644
--- a/server/src/com/cloud/network/firewall/FirewallManagerImpl.java
+++ b/server/src/com/cloud/network/firewall/FirewallManagerImpl.java
@@ -40,7 +40,7 @@
 import com.cloud.domain.dao.DomainDao;
 import com.cloud.event.ActionEvent;
 import com.cloud.event.EventTypes;
-import com.cloud.event.UsageEventVO;
+import com.cloud.event.UsageEventUtils;
 import com.cloud.event.dao.EventDao;
 import com.cloud.event.dao.UsageEventDao;
 import com.cloud.exception.InvalidParameterValueException;
@@ -61,18 +61,12 @@
 import com.cloud.network.dao.IPAddressDao;
 import com.cloud.network.element.FirewallServiceProvider;
 import com.cloud.network.element.NetworkACLServiceProvider;
-import com.cloud.network.element.NetworkElement;
 import com.cloud.network.element.PortForwardingServiceProvider;
 import com.cloud.network.element.StaticNatServiceProvider;
-import com.cloud.network.rules.FirewallManager;
-import com.cloud.network.rules.FirewallRule;
+import com.cloud.network.rules.*;
 import com.cloud.network.rules.FirewallRule.FirewallRuleType;
 import com.cloud.network.rules.FirewallRule.Purpose;
 import com.cloud.network.rules.FirewallRule.State;
-import com.cloud.network.rules.FirewallRuleVO;
-import com.cloud.network.rules.PortForwardingRule;
-import com.cloud.network.rules.PortForwardingRuleVO;
-import com.cloud.network.rules.StaticNat;
 import com.cloud.network.rules.dao.PortForwardingRulesDao;
 import com.cloud.network.vpc.VpcManager;
 import com.cloud.projects.Project.ListProjectResourcesCriteria;
@@ -88,17 +82,18 @@
 import com.cloud.utils.component.Adapters;
 import com.cloud.utils.component.Inject;
 import com.cloud.utils.component.Manager;
-import com.cloud.utils.db.DB;
-import com.cloud.utils.db.Filter;
-import com.cloud.utils.db.JoinBuilder;
-import com.cloud.utils.db.SearchBuilder;
-import com.cloud.utils.db.SearchCriteria;
+import com.cloud.utils.db.*;
 import com.cloud.utils.db.SearchCriteria.Op;
-import com.cloud.utils.db.Transaction;
 import com.cloud.utils.exception.CloudRuntimeException;
 import com.cloud.utils.net.NetUtils;
 import com.cloud.vm.UserVmVO;
 import com.cloud.vm.dao.UserVmDao;
+import org.apache.cloudstack.api.command.user.firewall.ListFirewallRulesCmd;
+import org.apache.log4j.Logger;
+
+import javax.ejb.Local;
+import javax.naming.ConfigurationException;
+import java.util.*;
 
 @Local(value = { FirewallService.class, FirewallManager.class})
 public class FirewallManagerImpl implements FirewallService, FirewallManager, NetworkRuleApplier, Manager {
@@ -709,8 +704,8 @@
         }
 
         if (generateUsageEvent && needUsageEvent) {
-            UsageEventVO usageEvent = new UsageEventVO(EventTypes.EVENT_NET_RULE_DELETE, rule.getAccountId(), 0, rule.getId(), null);
-            _usageEventDao.persist(usageEvent);
+            UsageEventUtils.publishUsageEvent(EventTypes.EVENT_NET_RULE_DELETE, rule.getAccountId(), 0, rule.getId(),
+                    null, rule.getClass().getName(), rule.getUuid());
         }
 
         txn.commit();
diff --git a/server/src/com/cloud/network/guru/ExternalGuestNetworkGuru.java b/server/src/com/cloud/network/guru/ExternalGuestNetworkGuru.java
index f8a8a95..bd6305d 100644
--- a/server/src/com/cloud/network/guru/ExternalGuestNetworkGuru.java
+++ b/server/src/com/cloud/network/guru/ExternalGuestNetworkGuru.java
@@ -20,17 +20,16 @@
 
 import javax.ejb.Local;
 
+import com.cloud.event.ActionEventUtils;
 import org.apache.log4j.Logger;
 
 import com.cloud.configuration.Config;
-import com.cloud.configuration.dao.ConfigurationDao;
 import com.cloud.dc.DataCenter;
 import com.cloud.dc.DataCenter.NetworkType;
 import com.cloud.dc.dao.DataCenterDao;
 import com.cloud.deploy.DeployDestination;
 import com.cloud.deploy.DeploymentPlan;
 import com.cloud.event.EventTypes;
-import com.cloud.event.EventUtils;
 import com.cloud.event.EventVO;
 import com.cloud.exception.InsufficientAddressCapacityException;
 import com.cloud.exception.InsufficientVirtualNetworkCapcityException;
@@ -42,9 +41,7 @@
 import com.cloud.network.Networks.BroadcastDomainType;
 import com.cloud.network.PhysicalNetwork;
 import com.cloud.network.PhysicalNetwork.IsolationMethod;
-import com.cloud.network.PhysicalNetworkVO;
 import com.cloud.network.dao.NetworkDao;
-import com.cloud.network.dao.PhysicalNetworkDao;
 import com.cloud.network.rules.PortForwardingRuleVO;
 import com.cloud.network.rules.dao.PortForwardingRulesDao;
 import com.cloud.offering.NetworkOffering;
@@ -142,7 +139,7 @@
             }
 
             implemented.setBroadcastUri(BroadcastDomainType.Vlan.toUri(vlanTag));
-            EventUtils.saveEvent(UserContext.current().getCallerUserId(), config.getAccountId(), EventVO.LEVEL_INFO, EventTypes.EVENT_ZONE_VLAN_ASSIGN, "Assigned Zone Vlan: "+vnet+ " Network Id: "+config.getId(), 0);
+            ActionEventUtils.onCompletedActionEvent(UserContext.current().getCallerUserId(), config.getAccountId(), EventVO.LEVEL_INFO, EventTypes.EVENT_ZONE_VLAN_ASSIGN, "Assigned Zone Vlan: " + vnet + " Network Id: " + config.getId(), 0);
         } else {
             vlanTag = Integer.parseInt(config.getBroadcastUri().getHost());
             implemented.setBroadcastUri(config.getBroadcastUri());
diff --git a/server/src/com/cloud/network/guru/GuestNetworkGuru.java b/server/src/com/cloud/network/guru/GuestNetworkGuru.java
index 9587885..e5371f5 100755
--- a/server/src/com/cloud/network/guru/GuestNetworkGuru.java
+++ b/server/src/com/cloud/network/guru/GuestNetworkGuru.java
@@ -19,12 +19,12 @@
 import java.util.ArrayList;
 import java.util.List;
 import java.util.Random;
-import java.util.Set;
 import java.util.SortedSet;
 import java.util.TreeSet;
 
 import javax.ejb.Local;
 
+import com.cloud.event.ActionEventUtils;
 import org.apache.log4j.Logger;
 
 import com.cloud.configuration.Config;
@@ -36,7 +36,6 @@
 import com.cloud.deploy.DeployDestination;
 import com.cloud.deploy.DeploymentPlan;
 import com.cloud.event.EventTypes;
-import com.cloud.event.EventUtils;
 import com.cloud.event.EventVO;
 import com.cloud.exception.InsufficientAddressCapacityException;
 import com.cloud.exception.InsufficientVirtualNetworkCapcityException;
@@ -298,8 +297,8 @@
                 		"part of network " + network + " implement ", DataCenter.class, dcId);
             }
             implemented.setBroadcastUri(BroadcastDomainType.Vlan.toUri(vnet));
-            EventUtils.saveEvent(UserContext.current().getCallerUserId(), network.getAccountId(), 
-                    EventVO.LEVEL_INFO, EventTypes.EVENT_ZONE_VLAN_ASSIGN, "Assigned Zone Vlan: "+vnet+ " Network Id: "+network.getId(), 0);
+            ActionEventUtils.onCompletedActionEvent(UserContext.current().getCallerUserId(), network.getAccountId(),
+                    EventVO.LEVEL_INFO, EventTypes.EVENT_ZONE_VLAN_ASSIGN, "Assigned Zone Vlan: " + vnet + " Network Id: " + network.getId(), 0);
         } else {
             implemented.setBroadcastUri(network.getBroadcastUri());
         }
@@ -433,9 +432,9 @@
         	s_logger.debug("Releasing vnet for the network id=" + profile.getId());
             _dcDao.releaseVnet(profile.getBroadcastUri().getHost(), profile.getDataCenterId(), 
                     profile.getPhysicalNetworkId(), profile.getAccountId(), profile.getReservationId());
-            EventUtils.saveEvent(UserContext.current().getCallerUserId(), profile.getAccountId(), 
+            ActionEventUtils.onCompletedActionEvent(UserContext.current().getCallerUserId(), profile.getAccountId(),
                     EventVO.LEVEL_INFO, EventTypes.EVENT_ZONE_VLAN_RELEASE, "Released Zone Vlan: "
-                    +profile.getBroadcastUri().getHost()+" for Network: "+profile.getId(), 0);
+                    + profile.getBroadcastUri().getHost() + " for Network: " + profile.getId(), 0);
         }
         profile.setBroadcastUri(null);
     }
diff --git a/server/src/com/cloud/network/lb/LoadBalancingRulesManagerImpl.java b/server/src/com/cloud/network/lb/LoadBalancingRulesManagerImpl.java
index 482c1fe..8e47545 100755
--- a/server/src/com/cloud/network/lb/LoadBalancingRulesManagerImpl.java
+++ b/server/src/com/cloud/network/lb/LoadBalancingRulesManagerImpl.java
@@ -30,6 +30,7 @@
 import javax.ejb.Local;
 import javax.naming.ConfigurationException;
 
+import com.cloud.event.UsageEventUtils;
 import org.apache.cloudstack.api.command.user.loadbalancer.*;
 import org.apache.log4j.Logger;
 
@@ -47,7 +48,6 @@
 import com.cloud.domain.dao.DomainDao;
 import com.cloud.event.ActionEvent;
 import com.cloud.event.EventTypes;
-import com.cloud.event.UsageEventVO;
 import com.cloud.event.dao.EventDao;
 import com.cloud.event.dao.UsageEventDao;
 import com.cloud.exception.InsufficientAddressCapacityException;
@@ -93,7 +93,6 @@
 import com.cloud.network.dao.NetworkDao;
 import com.cloud.network.dao.NetworkServiceMapDao;
 import com.cloud.network.element.LoadBalancingServiceProvider;
-import com.cloud.network.element.NetworkElement;
 import com.cloud.network.lb.LoadBalancingRule.LbAutoScalePolicy;
 import com.cloud.network.lb.LoadBalancingRule.LbAutoScaleVmGroup;
 import com.cloud.network.lb.LoadBalancingRule.LbAutoScaleVmProfile;
@@ -871,8 +870,8 @@
 
         if (generateUsageEvent) {
             // Generate usage event right after all rules were marked for revoke
-            UsageEventVO usageEvent = new UsageEventVO(EventTypes.EVENT_LOAD_BALANCER_DELETE, lb.getAccountId(), 0, lb.getId(), null);
-            _usageEventDao.persist(usageEvent);
+            UsageEventUtils.publishUsageEvent(EventTypes.EVENT_LOAD_BALANCER_DELETE, lb.getAccountId(), 0, lb.getId(),
+                    null, LoadBalancingRule.class.getName(), lb.getUuid());
         }
 
         txn.commit();
@@ -1104,8 +1103,8 @@
             }
             s_logger.debug("Load balancer " + newRule.getId() + " for Ip address id=" + sourceIpId + ", public port " + srcPortStart + ", private port " + defPortStart + " is added successfully.");
             UserContext.current().setEventDetails("Load balancer Id: " + newRule.getId());
-            UsageEventVO usageEvent = new UsageEventVO(EventTypes.EVENT_LOAD_BALANCER_CREATE, ipAddr.getAllocatedToAccountId(), ipAddr.getDataCenterId(), newRule.getId(), null);
-            _usageEventDao.persist(usageEvent);
+            UsageEventUtils.publishUsageEvent(EventTypes.EVENT_LOAD_BALANCER_CREATE, ipAddr.getAllocatedToAccountId(),
+                    ipAddr.getDataCenterId(), newRule.getId(), null, LoadBalancingRule.class.getName(), newRule.getUuid());
             txn.commit();
 
             return newRule;
diff --git a/server/src/com/cloud/network/rules/RulesManagerImpl.java b/server/src/com/cloud/network/rules/RulesManagerImpl.java
index fe86a8e..605ffd6 100755
--- a/server/src/com/cloud/network/rules/RulesManagerImpl.java
+++ b/server/src/com/cloud/network/rules/RulesManagerImpl.java
@@ -20,7 +20,7 @@
 import com.cloud.domain.dao.DomainDao;
 import com.cloud.event.ActionEvent;
 import com.cloud.event.EventTypes;
-import com.cloud.event.UsageEventVO;
+import com.cloud.event.UsageEventUtils;
 import com.cloud.event.dao.EventDao;
 import com.cloud.event.dao.UsageEventDao;
 import com.cloud.exception.InsufficientAddressCapacityException;
@@ -276,9 +276,9 @@
                     throw new CloudRuntimeException("Unable to update the state to add for " + newRule);
                 }
                 UserContext.current().setEventDetails("Rule Id: " + newRule.getId());
-                UsageEventVO usageEvent = new UsageEventVO(EventTypes.EVENT_NET_RULE_ADD, newRule.getAccountId(), 
-                        ipAddress.getDataCenterId(), newRule.getId(), null);
-                _usageEventDao.persist(usageEvent);
+                UsageEventUtils.publishUsageEvent(EventTypes.EVENT_NET_RULE_ADD, newRule.getAccountId(),
+                        ipAddress.getDataCenterId(), newRule.getId(), null, PortForwardingRule.class.getName(),
+                        newRule.getUuid());
                 txn.commit();
                 return newRule;
             } catch (Exception e) {
@@ -358,8 +358,8 @@
                 throw new CloudRuntimeException("Unable to update the state to add for " + newRule);
             }
             UserContext.current().setEventDetails("Rule Id: " + newRule.getId());
-            UsageEventVO usageEvent = new UsageEventVO(EventTypes.EVENT_NET_RULE_ADD, newRule.getAccountId(), 0, newRule.getId(), null);
-            _usageEventDao.persist(usageEvent);
+            UsageEventUtils.publishUsageEvent(EventTypes.EVENT_NET_RULE_ADD, newRule.getAccountId(), 0, newRule.getId(),
+                    null, FirewallRule.class.getName(), newRule.getUuid());
 
             txn.commit();
             StaticNatRule staticNatRule = new StaticNatRuleImpl(newRule, dstIp);
diff --git a/server/src/com/cloud/network/security/SecurityGroupManagerImpl.java b/server/src/com/cloud/network/security/SecurityGroupManagerImpl.java
index b564e3d..5635f52 100755
--- a/server/src/com/cloud/network/security/SecurityGroupManagerImpl.java
+++ b/server/src/com/cloud/network/security/SecurityGroupManagerImpl.java
@@ -16,30 +16,6 @@
 // under the License.
 package com.cloud.network.security;
 
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.Comparator;
-import java.util.Date;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.Iterator;
-import java.util.List;
-import java.util.Map;
-import java.util.Random;
-import java.util.Set;
-import java.util.TreeMap;
-import java.util.TreeSet;
-import java.util.concurrent.Executors;
-import java.util.concurrent.ScheduledExecutorService;
-import java.util.concurrent.TimeUnit;
-
-import javax.ejb.Local;
-import javax.naming.ConfigurationException;
-
-import org.apache.cloudstack.api.command.user.securitygroup.*;
-import org.apache.commons.codec.digest.DigestUtils;
-import org.apache.log4j.Logger;
-
 import com.cloud.agent.AgentManager;
 import com.cloud.agent.api.NetworkRulesSystemVmCommand;
 import com.cloud.agent.api.SecurityGroupRulesCmd;
@@ -47,33 +23,20 @@
 import com.cloud.agent.manager.Commands;
 import com.cloud.api.query.dao.SecurityGroupJoinDao;
 import com.cloud.api.query.vo.SecurityGroupJoinVO;
-
-import org.apache.cloudstack.api.command.user.securitygroup.RevokeSecurityGroupEgressCmd;
 import com.cloud.configuration.Config;
 import com.cloud.configuration.dao.ConfigurationDao;
 import com.cloud.domain.dao.DomainDao;
 import com.cloud.event.ActionEvent;
 import com.cloud.event.EventTypes;
-import com.cloud.event.UsageEventVO;
-import com.cloud.event.dao.UsageEventDao;
-import com.cloud.exception.AgentUnavailableException;
-import com.cloud.exception.InvalidParameterValueException;
-import com.cloud.exception.OperationTimedoutException;
-import com.cloud.exception.PermissionDeniedException;
-import com.cloud.exception.ResourceInUseException;
+import com.cloud.event.UsageEventUtils;
+import com.cloud.exception.*;
 import com.cloud.hypervisor.Hypervisor.HypervisorType;
 import com.cloud.network.Network;
 import com.cloud.network.NetworkManager;
 import com.cloud.network.NetworkModel;
 import com.cloud.network.security.SecurityGroupWork.Step;
 import com.cloud.network.security.SecurityRule.SecurityRuleType;
-import com.cloud.network.security.dao.SecurityGroupDao;
-import com.cloud.network.security.dao.SecurityGroupRuleDao;
-import com.cloud.network.security.dao.SecurityGroupRulesDao;
-import com.cloud.network.security.dao.SecurityGroupVMMapDao;
-import com.cloud.network.security.dao.SecurityGroupWorkDao;
-import com.cloud.network.security.dao.VmRulesetLogDao;
-import com.cloud.projects.Project.ListProjectResourcesCriteria;
+import com.cloud.network.security.dao.*;
 import com.cloud.projects.ProjectManager;
 import com.cloud.server.ManagementServer;
 import com.cloud.tags.dao.ResourceTagDao;
@@ -85,7 +48,6 @@
 import com.cloud.uservm.UserVm;
 import com.cloud.utils.NumbersUtil;
 import com.cloud.utils.Pair;
-import com.cloud.utils.Ternary;
 import com.cloud.utils.component.ComponentLocator;
 import com.cloud.utils.component.Inject;
 import com.cloud.utils.component.Manager;
@@ -93,26 +55,26 @@
 import com.cloud.utils.db.DB;
 import com.cloud.utils.db.Filter;
 import com.cloud.utils.db.GlobalLock;
-import com.cloud.utils.db.SearchBuilder;
-import com.cloud.utils.db.SearchCriteria;
 import com.cloud.utils.db.Transaction;
-import com.cloud.utils.db.SearchCriteria.Func;
 import com.cloud.utils.exception.CloudRuntimeException;
 import com.cloud.utils.fsm.StateListener;
 import com.cloud.utils.net.NetUtils;
-import com.cloud.vm.Nic;
-import com.cloud.vm.NicProfile;
-import com.cloud.vm.UserVmManager;
-import com.cloud.vm.UserVmVO;
-import com.cloud.vm.VMInstanceVO;
-import com.cloud.vm.VirtualMachine;
+import com.cloud.vm.*;
 import com.cloud.vm.VirtualMachine.Event;
 import com.cloud.vm.VirtualMachine.State;
-import com.cloud.vm.VirtualMachineManager;
 import com.cloud.vm.dao.UserVmDao;
 import com.cloud.vm.dao.VMInstanceDao;
-
 import edu.emory.mathcs.backport.java.util.Collections;
+import org.apache.cloudstack.api.command.user.securitygroup.*;
+import org.apache.commons.codec.digest.DigestUtils;
+import org.apache.log4j.Logger;
+
+import javax.ejb.Local;
+import javax.naming.ConfigurationException;
+import java.util.*;
+import java.util.concurrent.Executors;
+import java.util.concurrent.ScheduledExecutorService;
+import java.util.concurrent.TimeUnit;
 
 @Local(value = { SecurityGroupManager.class, SecurityGroupService.class })
 public class SecurityGroupManagerImpl implements SecurityGroupManager, SecurityGroupService, Manager, StateListener<State, VirtualMachine.Event, VirtualMachine> {
@@ -159,8 +121,6 @@
     @Inject
     ProjectManager _projectMgr;
     @Inject
-    UsageEventDao _usageEventDao;
-    @Inject
     ResourceTagDao _resourceTagDao;
 
     ScheduledExecutorService _executorPool;
@@ -460,8 +420,9 @@
         // For each group, find the security rules that allow the group
         for (SecurityGroupVMMapVO mapVO : groupsForVm) {// FIXME: use custom sql in the dao
         	//Add usage events for security group assign
-            UsageEventVO usageEvent = new UsageEventVO(EventTypes.EVENT_SECURITY_GROUP_ASSIGN, vm.getAccountId(), vm.getDataCenterIdToDeployIn(), vm.getId(), mapVO.getSecurityGroupId());
-            _usageEventDao.persist(usageEvent);
+            UsageEventUtils.publishUsageEvent(EventTypes.EVENT_SECURITY_GROUP_ASSIGN, vm.getAccountId(),
+                    vm.getDataCenterIdToDeployIn(), vm.getId(), mapVO.getSecurityGroupId(),
+                    vm.getClass().getName(), vm.getUuid());
 
             List<SecurityGroupRuleVO> allowingRules = _securityGroupRuleDao.listByAllowedSecurityGroupId(mapVO.getSecurityGroupId());
             // For each security rule that allows a group that the vm belongs to, find the group it belongs to
@@ -476,8 +437,9 @@
         // For each group, find the security rules rules that allow the group
         for (SecurityGroupVMMapVO mapVO : groupsForVm) {// FIXME: use custom sql in the dao
         	//Add usage events for security group remove
-            UsageEventVO usageEvent = new UsageEventVO(EventTypes.EVENT_SECURITY_GROUP_REMOVE, vm.getAccountId(), vm.getDataCenterIdToDeployIn(), vm.getId(), mapVO.getSecurityGroupId());
-            _usageEventDao.persist(usageEvent);
+            UsageEventUtils.publishUsageEvent(EventTypes.EVENT_SECURITY_GROUP_REMOVE,
+                    vm.getAccountId(), vm.getDataCenterIdToDeployIn(), vm.getId(), mapVO.getSecurityGroupId(),
+                    vm.getClass().getName(), vm.getUuid());
 
             List<SecurityGroupRuleVO> allowingRules = _securityGroupRuleDao.listByAllowedSecurityGroupId(mapVO.getSecurityGroupId());
             // For each security rule that allows a group that the vm belongs to, find the group it belongs to
diff --git a/server/src/com/cloud/network/vpn/RemoteAccessVpnManagerImpl.java b/server/src/com/cloud/network/vpn/RemoteAccessVpnManagerImpl.java
index e360bca..858c362 100755
--- a/server/src/com/cloud/network/vpn/RemoteAccessVpnManagerImpl.java
+++ b/server/src/com/cloud/network/vpn/RemoteAccessVpnManagerImpl.java
@@ -16,44 +16,24 @@
 // under the License.
 package com.cloud.network.vpn;
 
-import java.util.ArrayList;
-import java.util.Enumeration;
-import java.util.List;
-import java.util.Map;
-
-import javax.ejb.Local;
-import javax.naming.ConfigurationException;
-
-import org.apache.cloudstack.api.command.user.vpn.ListVpnUsersCmd;
-import org.apache.log4j.Logger;
-
-import org.apache.cloudstack.api.command.user.vpn.ListRemoteAccessVpnsCmd;
 import com.cloud.configuration.Config;
 import com.cloud.configuration.dao.ConfigurationDao;
 import com.cloud.domain.DomainVO;
 import com.cloud.domain.dao.DomainDao;
 import com.cloud.event.EventTypes;
-import com.cloud.event.UsageEventVO;
+import com.cloud.event.UsageEventUtils;
 import com.cloud.event.dao.UsageEventDao;
 import com.cloud.exception.AccountLimitException;
 import com.cloud.exception.InvalidParameterValueException;
 import com.cloud.exception.NetworkRuleConflictException;
 import com.cloud.exception.ResourceUnavailableException;
-import com.cloud.network.IPAddressVO;
-import com.cloud.network.Network;
+import com.cloud.network.*;
 import com.cloud.network.Network.Service;
-import com.cloud.network.NetworkModel;
-import com.cloud.network.PublicIpAddress;
-import com.cloud.network.RemoteAccessVpn;
-import com.cloud.network.RemoteAccessVpnVO;
-import com.cloud.network.VpnUser;
 import com.cloud.network.VpnUser.State;
-import com.cloud.network.VpnUserVO;
 import com.cloud.network.dao.FirewallRulesDao;
 import com.cloud.network.dao.IPAddressDao;
 import com.cloud.network.dao.RemoteAccessVpnDao;
 import com.cloud.network.dao.VpnUserDao;
-import com.cloud.network.element.NetworkElement;
 import com.cloud.network.element.RemoteAccessVPNServiceProvider;
 import com.cloud.network.rules.FirewallManager;
 import com.cloud.network.rules.FirewallRule;
@@ -74,14 +54,19 @@
 import com.cloud.utils.component.ComponentLocator;
 import com.cloud.utils.component.Inject;
 import com.cloud.utils.component.Manager;
-import com.cloud.utils.db.DB;
-import com.cloud.utils.db.Filter;
-import com.cloud.utils.db.JoinBuilder;
-import com.cloud.utils.db.SearchBuilder;
-import com.cloud.utils.db.SearchCriteria;
+import com.cloud.utils.db.*;
 import com.cloud.utils.db.SearchCriteria.Op;
-import com.cloud.utils.db.Transaction;
 import com.cloud.utils.net.NetUtils;
+import org.apache.cloudstack.api.command.user.vpn.ListRemoteAccessVpnsCmd;
+import org.apache.cloudstack.api.command.user.vpn.ListVpnUsersCmd;
+import org.apache.log4j.Logger;
+
+import javax.ejb.Local;
+import javax.naming.ConfigurationException;
+import java.util.ArrayList;
+import java.util.Enumeration;
+import java.util.List;
+import java.util.Map;
 
 @Local(value = RemoteAccessVpnService.class)
 public class RemoteAccessVpnManagerImpl implements RemoteAccessVpnService, Manager {
@@ -281,8 +266,8 @@
                         for(VpnUserVO user : vpnUsers){
                         	// VPN_USER_REMOVE event is already generated for users in Revoke state
                         	if(user.getState() != VpnUser.State.Revoke){
-                        		UsageEventVO usageEvent = new UsageEventVO(EventTypes.EVENT_VPN_USER_REMOVE, user.getAccountId(), 0, user.getId(), user.getUsername());
-                        		_usageEventDao.persist(usageEvent);
+                                UsageEventUtils.publishUsageEvent(EventTypes.EVENT_VPN_USER_REMOVE, user.getAccountId(),
+                                        0, user.getId(), user.getUsername(), user.getClass().getName(), user.getUuid());
                         	}
                         }
                         if (vpnFwRules != null) {
@@ -333,8 +318,8 @@
         }
         
         VpnUser user = _vpnUsersDao.persist(new VpnUserVO(vpnOwnerId, owner.getDomainId(), username, password));
-        UsageEventVO usageEvent = new UsageEventVO(EventTypes.EVENT_VPN_USER_ADD, user.getAccountId(), 0, user.getId(), user.getUsername());
-        _usageEventDao.persist(usageEvent);
+        UsageEventUtils.publishUsageEvent(EventTypes.EVENT_VPN_USER_ADD, user.getAccountId(), 0, user.getId(),
+                user.getUsername(), user.getClass().getName(), user.getUuid());
         txn.commit();
         return user;
     }
@@ -350,8 +335,8 @@
         txn.start();
         user.setState(State.Revoke);
         _vpnUsersDao.update(user.getId(), user);
-        UsageEventVO usageEvent = new UsageEventVO(EventTypes.EVENT_VPN_USER_REMOVE, user.getAccountId(), 0, user.getId(), user.getUsername());
-        _usageEventDao.persist(usageEvent);
+        UsageEventUtils.publishUsageEvent(EventTypes.EVENT_VPN_USER_REMOVE, user.getAccountId(), 0, user.getId(),
+                user.getUsername(), user.getClass().getName(), user.getUuid());
         txn.commit();
         return true;
     }
@@ -407,8 +392,8 @@
                 List<VpnUserVO> vpnUsers = _vpnUsersDao.listByAccount(vpn.getAccountId());
                 for(VpnUserVO user : vpnUsers){
                 	if(user.getState() != VpnUser.State.Revoke){
-                		UsageEventVO usageEvent = new UsageEventVO(EventTypes.EVENT_VPN_USER_ADD, user.getAccountId(), 0, user.getId(), user.getUsername());
-                		_usageEventDao.persist(usageEvent);
+                        UsageEventUtils.publishUsageEvent(EventTypes.EVENT_VPN_USER_ADD, user.getAccountId(), 0,
+                                user.getId(), user.getUsername(), user.getClass().getName(), user.getUuid());
                 	}
                 }
                 txn.commit();
@@ -483,8 +468,8 @@
                     Transaction txn = Transaction.currentTxn();
                     txn.start();            		
                     _vpnUsersDao.remove(user.getId());
-                    UsageEventVO usageEvent = new UsageEventVO(EventTypes.EVENT_VPN_USER_REMOVE, user.getAccountId(), 0, user.getId(), user.getUsername());
-                    _usageEventDao.persist(usageEvent);
+                    UsageEventUtils.publishUsageEvent(EventTypes.EVENT_VPN_USER_REMOVE, user.getAccountId(),
+                            0, user.getId(), user.getUsername(), user.getClass().getName(), user.getUuid());
                     txn.commit();
                 }
                 s_logger.warn("Failed to apply vpn for user " + user.getUsername() + ", accountId=" + user.getAccountId());
diff --git a/server/src/com/cloud/server/ManagementServerImpl.java b/server/src/com/cloud/server/ManagementServerImpl.java
index 40c5508..0b5c531 100755
--- a/server/src/com/cloud/server/ManagementServerImpl.java
+++ b/server/src/com/cloud/server/ManagementServerImpl.java
@@ -29,7 +29,6 @@
 import java.util.Enumeration;
 import java.util.HashMap;
 import java.util.HashSet;
-import java.util.Iterator;
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
@@ -42,6 +41,7 @@
 import javax.crypto.Mac;
 import javax.crypto.spec.SecretKeySpec;
 
+import com.cloud.event.ActionEventUtils;
 import org.apache.cloudstack.api.BaseUpdateTemplateOrIsoCmd;
 import org.apache.cloudstack.api.command.admin.cluster.ListClustersCmd;
 import org.apache.cloudstack.api.command.admin.config.ListCfgsByCmd;
@@ -60,7 +60,6 @@
 import org.apache.cloudstack.api.command.user.template.ListTemplatesCmd;
 import org.apache.cloudstack.api.command.user.template.UpdateTemplateCmd;
 import org.apache.cloudstack.api.command.user.vm.GetVMPasswordCmd;
-import org.apache.cloudstack.api.command.user.zone.ListZonesByCmd;
 import org.apache.commons.codec.binary.Base64;
 import org.apache.log4j.Logger;
 
@@ -128,7 +127,6 @@
 import com.cloud.domain.dao.DomainDao;
 import com.cloud.event.ActionEvent;
 import com.cloud.event.EventTypes;
-import com.cloud.event.EventUtils;
 import com.cloud.event.EventVO;
 import com.cloud.event.dao.EventDao;
 import com.cloud.exception.ConcurrentOperationException;
@@ -230,7 +228,6 @@
 import com.cloud.utils.net.NetUtils;
 import com.cloud.utils.ssh.SSHKeysHelper;
 import com.cloud.vm.ConsoleProxyVO;
-import com.cloud.vm.DomainRouterVO;
 import com.cloud.vm.InstanceGroupVO;
 import com.cloud.vm.SecondaryStorageVmVO;
 import com.cloud.vm.UserVmVO;
@@ -2422,12 +2419,12 @@
 
     @Override
     public Long saveStartedEvent(Long userId, Long accountId, String type, String description, long startEventId) {
-        return EventUtils.saveStartedEvent(userId, accountId, type, description, startEventId);
+        return ActionEventUtils.onStartedActionEvent(userId, accountId, type, description, startEventId);
     }
 
     @Override
     public Long saveCompletedEvent(Long userId, Long accountId, String level, String type, String description, long startEventId) {
-        return EventUtils.saveEvent(userId, accountId, level, type, description, startEventId);
+        return ActionEventUtils.onCompletedActionEvent(userId, accountId, level, type, description, startEventId);
     }
 
     @Override
diff --git a/server/src/com/cloud/storage/StorageManagerImpl.java b/server/src/com/cloud/storage/StorageManagerImpl.java
index 07f4d8a..5a799f9 100755
--- a/server/src/com/cloud/storage/StorageManagerImpl.java
+++ b/server/src/com/cloud/storage/StorageManagerImpl.java
@@ -16,68 +16,14 @@
 // under the License.
 package com.cloud.storage;
 
-import java.math.BigDecimal;
-import java.net.Inet6Address;
-import java.net.InetAddress;
-import java.net.URI;
-import java.net.URISyntaxException;
-import java.net.UnknownHostException;
-import java.sql.PreparedStatement;
-import java.sql.ResultSet;
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.Date;
-import java.util.Enumeration;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.Iterator;
-import java.util.List;
-import java.util.Map;
-import java.util.Random;
-import java.util.Set;
-import java.util.UUID;
-import java.util.concurrent.Executors;
-import java.util.concurrent.ScheduledExecutorService;
-import java.util.concurrent.TimeUnit;
-
-import javax.ejb.Local;
-import javax.naming.ConfigurationException;
-
-import org.apache.cloudstack.api.command.admin.storage.*;
-import org.apache.cloudstack.api.command.user.volume.CreateVolumeCmd;
-import org.apache.cloudstack.api.command.user.volume.UploadVolumeCmd;
-import org.apache.cloudstack.api.command.user.volume.ResizeVolumeCmd;
-import org.apache.log4j.Logger;
-
 import com.cloud.agent.AgentManager;
-import com.cloud.agent.api.Answer;
-import com.cloud.agent.api.BackupSnapshotCommand;
-import com.cloud.agent.api.CleanupSnapshotBackupCommand;
-import com.cloud.agent.api.Command;
-import com.cloud.agent.api.CreateStoragePoolCommand;
-import com.cloud.agent.api.CreateVolumeFromSnapshotAnswer;
-import com.cloud.agent.api.CreateVolumeFromSnapshotCommand;
-import com.cloud.agent.api.DeleteStoragePoolCommand;
-import com.cloud.agent.api.ManageSnapshotCommand;
-import com.cloud.agent.api.ModifyStoragePoolAnswer;
-import com.cloud.agent.api.ModifyStoragePoolCommand;
-import com.cloud.agent.api.UpgradeSnapshotCommand;
-import com.cloud.agent.api.storage.CopyVolumeAnswer;
-import com.cloud.agent.api.storage.CopyVolumeCommand;
-import com.cloud.agent.api.storage.CreateAnswer;
-import com.cloud.agent.api.storage.CreateCommand;
-import com.cloud.agent.api.storage.DeleteTemplateCommand;
-import com.cloud.agent.api.storage.DeleteVolumeCommand;
-import com.cloud.agent.api.storage.DestroyCommand;
-import com.cloud.agent.api.storage.ResizeVolumeCommand;
-import com.cloud.agent.api.storage.ResizeVolumeAnswer;
+import com.cloud.agent.api.*;
+import com.cloud.agent.api.storage.*;
 import com.cloud.agent.api.to.StorageFilerTO;
 import com.cloud.agent.api.to.VolumeTO;
 import com.cloud.agent.manager.Commands;
 import com.cloud.alert.AlertManager;
 import com.cloud.api.ApiDBUtils;
-import org.apache.cloudstack.api.command.admin.storage.CreateStoragePoolCmd;
 import com.cloud.async.AsyncJobManager;
 import com.cloud.capacity.Capacity;
 import com.cloud.capacity.CapacityManager;
@@ -104,21 +50,9 @@
 import com.cloud.domain.dao.DomainDao;
 import com.cloud.event.ActionEvent;
 import com.cloud.event.EventTypes;
-import com.cloud.event.UsageEventVO;
+import com.cloud.event.UsageEventUtils;
 import com.cloud.event.dao.EventDao;
-import com.cloud.event.dao.UsageEventDao;
-import com.cloud.exception.AgentUnavailableException;
-import com.cloud.exception.ConcurrentOperationException;
-import com.cloud.exception.DiscoveryException;
-import com.cloud.exception.InsufficientCapacityException;
-import com.cloud.exception.InsufficientStorageCapacityException;
-import com.cloud.exception.InvalidParameterValueException;
-import com.cloud.exception.OperationTimedoutException;
-import com.cloud.exception.PermissionDeniedException;
-import com.cloud.exception.ResourceAllocationException;
-import com.cloud.exception.ResourceInUseException;
-import com.cloud.exception.ResourceUnavailableException;
-import com.cloud.exception.StorageUnavailableException;
+import com.cloud.exception.*;
 import com.cloud.host.Host;
 import com.cloud.host.HostVO;
 import com.cloud.host.Status;
@@ -140,32 +74,17 @@
 import com.cloud.storage.Volume.Event;
 import com.cloud.storage.Volume.Type;
 import com.cloud.storage.allocator.StoragePoolAllocator;
-import com.cloud.storage.dao.DiskOfferingDao;
-import com.cloud.storage.dao.SnapshotDao;
-import com.cloud.storage.dao.SnapshotPolicyDao;
-import com.cloud.storage.dao.StoragePoolDao;
-import com.cloud.storage.dao.StoragePoolHostDao;
-import com.cloud.storage.dao.StoragePoolWorkDao;
-import com.cloud.storage.dao.VMTemplateDao;
-import com.cloud.storage.dao.VMTemplateHostDao;
-import com.cloud.storage.dao.VMTemplatePoolDao;
-import com.cloud.storage.dao.VMTemplateS3Dao;
-import com.cloud.storage.dao.VMTemplateSwiftDao;
-import com.cloud.storage.dao.VolumeDao;
-import com.cloud.storage.dao.VolumeHostDao;
+import com.cloud.storage.dao.*;
 import com.cloud.storage.download.DownloadMonitor;
 import com.cloud.storage.listener.StoragePoolMonitor;
+import com.cloud.storage.listener.VolumeStateListener;
 import com.cloud.storage.s3.S3Manager;
 import com.cloud.storage.secondary.SecondaryStorageVmManager;
 import com.cloud.storage.snapshot.SnapshotManager;
 import com.cloud.storage.snapshot.SnapshotScheduler;
 import com.cloud.tags.dao.ResourceTagDao;
 import com.cloud.template.TemplateManager;
-import com.cloud.user.Account;
-import com.cloud.user.AccountManager;
-import com.cloud.user.ResourceLimitService;
-import com.cloud.user.User;
-import com.cloud.user.UserContext;
+import com.cloud.user.*;
 import com.cloud.user.dao.AccountDao;
 import com.cloud.user.dao.UserDao;
 import com.cloud.uservm.UserVm;
@@ -178,36 +97,35 @@
 import com.cloud.utils.component.Inject;
 import com.cloud.utils.component.Manager;
 import com.cloud.utils.concurrency.NamedThreadFactory;
-import com.cloud.utils.db.DB;
-import com.cloud.utils.db.GenericSearchBuilder;
-import com.cloud.utils.db.GlobalLock;
-import com.cloud.utils.db.JoinBuilder;
+import com.cloud.utils.db.*;
 import com.cloud.utils.db.JoinBuilder.JoinType;
-import com.cloud.utils.db.SearchBuilder;
-import com.cloud.utils.db.SearchCriteria;
 import com.cloud.utils.db.SearchCriteria.Op;
-import com.cloud.utils.db.Transaction;
 import com.cloud.utils.exception.CloudRuntimeException;
 import com.cloud.utils.exception.ExecutionException;
 import com.cloud.utils.fsm.NoTransitionException;
 import com.cloud.utils.fsm.StateMachine2;
-import com.cloud.vm.ConsoleProxyVO;
-import com.cloud.vm.DiskProfile;
-import com.cloud.vm.DomainRouterVO;
-import com.cloud.vm.SecondaryStorageVmVO;
-import com.cloud.vm.UserVmManager;
-import com.cloud.vm.UserVmVO;
-import com.cloud.vm.VMInstanceVO;
-import com.cloud.vm.VirtualMachine;
+import com.cloud.vm.*;
 import com.cloud.vm.VirtualMachine.State;
-import com.cloud.vm.VirtualMachineManager;
-import com.cloud.vm.VirtualMachineProfile;
-import com.cloud.vm.VirtualMachineProfileImpl;
-import com.cloud.vm.dao.ConsoleProxyDao;
-import com.cloud.vm.dao.DomainRouterDao;
-import com.cloud.vm.dao.SecondaryStorageVmDao;
-import com.cloud.vm.dao.UserVmDao;
-import com.cloud.vm.dao.VMInstanceDao;
+import com.cloud.vm.dao.*;
+import org.apache.cloudstack.api.command.admin.storage.CancelPrimaryStorageMaintenanceCmd;
+import org.apache.cloudstack.api.command.admin.storage.CreateStoragePoolCmd;
+import org.apache.cloudstack.api.command.admin.storage.DeletePoolCmd;
+import org.apache.cloudstack.api.command.admin.storage.UpdateStoragePoolCmd;
+import org.apache.cloudstack.api.command.user.volume.CreateVolumeCmd;
+import org.apache.cloudstack.api.command.user.volume.ResizeVolumeCmd;
+import org.apache.cloudstack.api.command.user.volume.UploadVolumeCmd;
+import org.apache.log4j.Logger;
+
+import javax.ejb.Local;
+import javax.naming.ConfigurationException;
+import java.math.BigDecimal;
+import java.net.*;
+import java.sql.PreparedStatement;
+import java.sql.ResultSet;
+import java.util.*;
+import java.util.concurrent.Executors;
+import java.util.concurrent.ScheduledExecutorService;
+import java.util.concurrent.TimeUnit;
 
 @Local(value = { StorageManager.class, StorageService.class })
 public class StorageManagerImpl implements StorageManager, Manager, ClusterManagerListener {
@@ -301,8 +219,6 @@
     @Inject
     protected ClusterDao _clusterDao;
     @Inject
-    protected UsageEventDao _usageEventDao;
-    @Inject
     protected VirtualMachineManager _vmMgr;
     @Inject
     protected DomainRouterDao _domrDao;
@@ -653,9 +569,9 @@
         Pair<VolumeVO, String> volumeDetails = createVolumeFromSnapshot(volume, snapshot);
         if (volumeDetails != null) {
             createdVolume = volumeDetails.first();
-        	UsageEventVO usageEvent = new UsageEventVO(EventTypes.EVENT_VOLUME_CREATE, createdVolume.getAccountId(), createdVolume.getDataCenterId(), createdVolume.getId(), createdVolume.getName(),
-        			                                   createdVolume.getDiskOfferingId(), null, createdVolume.getSize());
-        	_usageEventDao.persist(usageEvent);
+            UsageEventUtils.publishUsageEvent(EventTypes.EVENT_VOLUME_CREATE, createdVolume.getAccountId(),
+                    createdVolume.getDataCenterId(), createdVolume.getId(), createdVolume.getName(), createdVolume.getDiskOfferingId(),
+                    null, createdVolume.getSize(), Volume.class.getName(), createdVolume.getUuid());
         }
         return createdVolume;
     }
@@ -775,8 +691,9 @@
         volume.setPoolId(destPool.getId());
         volume.setPodId(destPool.getPodId());
         stateTransitTo(volume, Event.CopySucceeded);
-        UsageEventVO usageEvent = new UsageEventVO(EventTypes.EVENT_VOLUME_CREATE, volume.getAccountId(), volume.getDataCenterId(), volume.getId(), volume.getName(), volume.getDiskOfferingId(), null, volume.getSize());
-        _usageEventDao.persist(usageEvent);
+        UsageEventUtils.publishUsageEvent(EventTypes.EVENT_VOLUME_CREATE, volume.getAccountId(),
+                volume.getDataCenterId(), volume.getId(), volume.getName(), volume.getDiskOfferingId(),
+                null, volume.getSize(), Volume.class.getName(), volume.getUuid());
         _volumeHostDao.remove(volumeHostVO.getId());
     	txn.commit();
 		return volume;
@@ -1050,6 +967,9 @@
         LocalStorageSearch.join("poolHost", storageHostSearch, storageHostSearch.entity().getPoolId(), LocalStorageSearch.entity().getId(), JoinBuilder.JoinType.INNER);
         LocalStorageSearch.and("type", LocalStorageSearch.entity().getPoolType(), SearchCriteria.Op.IN);
         LocalStorageSearch.done();
+
+        Volume.State.getStateMachine().registerListener( new VolumeStateListener());
+
         return true;
     }
 
@@ -1967,8 +1887,8 @@
                 throw new InvalidParameterValueException("unable to find a snapshot with id " + snapshotId);
             }
 
-            if (snapshotCheck.getStatus() != Snapshot.Status.BackedUp) {
-                throw new InvalidParameterValueException("Snapshot id=" + snapshotId + " is not in " + Snapshot.Status.BackedUp + " state yet and can't be used for volume creation");
+            if (snapshotCheck.getState() != Snapshot.State.BackedUp) {
+                throw new InvalidParameterValueException("Snapshot id=" + snapshotId + " is not in " + Snapshot.State.BackedUp + " state yet and can't be used for volume creation");
             }
 
             diskOfferingId = snapshotCheck.getDiskOfferingId();
@@ -2058,9 +1978,10 @@
 
         volume = _volsDao.persist(volume);
         if(cmd.getSnapshotId() == null){
-        	//for volume created from snapshot, create usage event after volume creation
-        	UsageEventVO usageEvent = new UsageEventVO(EventTypes.EVENT_VOLUME_CREATE, volume.getAccountId(), volume.getDataCenterId(), volume.getId(), volume.getName(), diskOfferingId, null, size);
-        	_usageEventDao.persist(usageEvent);
+            //for volume created from snapshot, create usage event after volume creation
+            UsageEventUtils.publishUsageEvent(EventTypes.EVENT_VOLUME_CREATE, volume.getAccountId(),
+                    volume.getDataCenterId(), volume.getId(), volume.getName(), diskOfferingId, null, size,
+                    Volume.class.getName(), volume.getUuid());
         }
 
         UserContext.current().setEventDetails("Volume Id: " + volume.getId());
@@ -2305,8 +2226,9 @@
             // Decrement the resource count for volumes belonging user VM's only
             _resourceLimitMgr.decrementResourceCount(volume.getAccountId(), ResourceType.volume);
             // Log usage event for volumes belonging user VM's only
-            UsageEventVO usageEvent = new UsageEventVO(EventTypes.EVENT_VOLUME_DELETE, volume.getAccountId(), volume.getDataCenterId(), volume.getId(), volume.getName());
-            _usageEventDao.persist(usageEvent);
+            UsageEventUtils.publishUsageEvent(EventTypes.EVENT_VOLUME_DELETE, volume.getAccountId(),
+                    volume.getDataCenterId(), volume.getId(), volume.getName(),
+                    Volume.class.getName(), volume.getUuid());
         }
 
         try {
@@ -2471,7 +2393,7 @@
                     }
 
                     // remove snapshots in Error state
-                    List<SnapshotVO> snapshots = _snapshotDao.listAllByStatus(Snapshot.Status.Error);
+                    List<SnapshotVO> snapshots = _snapshotDao.listAllByStatus(Snapshot.State.Error);
                     for (SnapshotVO snapshotVO : snapshots) {
                         try{
                             _snapshotDao.expunge(snapshotVO.getId());
@@ -3140,10 +3062,9 @@
 
         // Save usage event and update resource count for user vm volumes
         if (vm instanceof UserVm) {
-
-            UsageEventVO usageEvent = new UsageEventVO(EventTypes.EVENT_VOLUME_CREATE, vol.getAccountId(), vol.getDataCenterId(), vol.getId(), vol.getName(), offering.getId(), null, size);
-            _usageEventDao.persist(usageEvent);
-
+            UsageEventUtils.publishUsageEvent(EventTypes.EVENT_VOLUME_CREATE, vol.getAccountId(),
+                    vol.getDataCenterId(), vol.getId(), vol.getName(), offering.getId(), null, size,
+                    Volume.class.getName(), vol.getUuid());
             _resourceLimitMgr.incrementResourceCount(vm.getAccountId(), ResourceType.volume);
         }
         return toDiskProfile(vol, offering);
@@ -3204,9 +3125,9 @@
                 offeringId = offering.getId();
             }
 
-            UsageEventVO usageEvent = new UsageEventVO(EventTypes.EVENT_VOLUME_CREATE, vol.getAccountId(), vol.getDataCenterId(), vol.getId(), vol.getName(), offeringId, template.getId(),
-                    vol.getSize());
-            _usageEventDao.persist(usageEvent);
+            UsageEventUtils.publishUsageEvent(EventTypes.EVENT_VOLUME_CREATE, vol.getAccountId(),
+                    vol.getDataCenterId(), vol.getId(), vol.getName(), offeringId, template.getId(),
+                    vol.getSize(), Volume.class.getName(), vol.getUuid());
 
             _resourceLimitMgr.incrementResourceCount(vm.getAccountId(), ResourceType.volume);
         }
diff --git a/server/src/com/cloud/storage/dao/SnapshotDao.java b/server/src/com/cloud/storage/dao/SnapshotDao.java
index b32d278..3b961f6 100644
--- a/server/src/com/cloud/storage/dao/SnapshotDao.java
+++ b/server/src/com/cloud/storage/dao/SnapshotDao.java
@@ -16,15 +16,16 @@
 // under the License.
 package com.cloud.storage.dao;
 
-import java.util.List;
-
 import com.cloud.storage.Snapshot;
 import com.cloud.storage.Snapshot.Type;
 import com.cloud.storage.SnapshotVO;
 import com.cloud.utils.db.Filter;
 import com.cloud.utils.db.GenericDao;
+import com.cloud.utils.fsm.StateDao;
 
-public interface SnapshotDao extends GenericDao<SnapshotVO, Long> {
+import java.util.List;
+
+public interface SnapshotDao extends GenericDao<SnapshotVO, Long>, StateDao<Snapshot.State, Snapshot.Event, Snapshot> {
 	List<SnapshotVO> listByVolumeId(long volumeId);
 	List<SnapshotVO> listByVolumeId(Filter filter, long volumeId);
 	SnapshotVO findNextSnapshot(long parentSnapId);
@@ -39,7 +40,7 @@
     List<SnapshotVO> listByHostId(Filter filter, long hostId);
     List<SnapshotVO> listByHostId(long hostId);
     public Long countSnapshotsForAccount(long accountId);
-	List<SnapshotVO> listByInstanceId(long instanceId, Snapshot.Status... status);
-	List<SnapshotVO> listByStatus(long volumeId, Snapshot.Status... status);
-    List<SnapshotVO> listAllByStatus(Snapshot.Status... status);
+	List<SnapshotVO> listByInstanceId(long instanceId, Snapshot.State... status);
+	List<SnapshotVO> listByStatus(long volumeId, Snapshot.State... status);
+    List<SnapshotVO> listAllByStatus(Snapshot.State... status);
 }
diff --git a/server/src/com/cloud/storage/dao/SnapshotDaoImpl.java b/server/src/com/cloud/storage/dao/SnapshotDaoImpl.java
index 65e2f5f..3fe1aba 100644
--- a/server/src/com/cloud/storage/dao/SnapshotDaoImpl.java
+++ b/server/src/com/cloud/storage/dao/SnapshotDaoImpl.java
@@ -16,33 +16,27 @@
 // under the License.
 package com.cloud.storage.dao;
 
-import java.sql.PreparedStatement;
-import java.sql.ResultSet;
-import java.util.List;
-
-import javax.ejb.Local;
-
-import org.apache.log4j.Logger;
-
 import com.cloud.server.ResourceTag.TaggedResourceType;
 import com.cloud.storage.Snapshot;
+import com.cloud.storage.Snapshot.Event;
+import com.cloud.storage.Snapshot.State;
 import com.cloud.storage.Snapshot.Type;
 import com.cloud.storage.SnapshotVO;
 import com.cloud.storage.Volume;
 import com.cloud.storage.VolumeVO;
 import com.cloud.tags.dao.ResourceTagsDaoImpl;
 import com.cloud.utils.component.ComponentLocator;
-import com.cloud.utils.db.DB;
-import com.cloud.utils.db.Filter;
-import com.cloud.utils.db.GenericDaoBase;
-import com.cloud.utils.db.GenericSearchBuilder;
+import com.cloud.utils.db.*;
 import com.cloud.utils.db.JoinBuilder.JoinType;
-import com.cloud.utils.db.SearchBuilder;
-import com.cloud.utils.db.SearchCriteria;
 import com.cloud.utils.db.SearchCriteria.Func;
-import com.cloud.utils.db.Transaction;
 import com.cloud.vm.VMInstanceVO;
 import com.cloud.vm.dao.VMInstanceDaoImpl;
+import org.apache.log4j.Logger;
+
+import javax.ejb.Local;
+import java.sql.PreparedStatement;
+import java.sql.ResultSet;
+import java.util.List;
 
 @Local (value={SnapshotDao.class})
 public class SnapshotDaoImpl extends GenericDaoBase<SnapshotVO, Long> implements SnapshotDao {
@@ -113,7 +107,7 @@
     public List<SnapshotVO> listByHostId(Filter filter, long hostId ) {
         SearchCriteria<SnapshotVO> sc = HostIdSearch.create();
         sc.setParameters("hostId", hostId);
-        sc.setParameters("status", Snapshot.Status.BackedUp);
+        sc.setParameters("status", Snapshot.State.BackedUp);
         return listBy(sc, filter);
     }
         
@@ -145,7 +139,7 @@
         
         HostIdSearch = createSearchBuilder();
         HostIdSearch.and("hostId", HostIdSearch.entity().getSecHostId(), SearchCriteria.Op.EQ);
-        HostIdSearch.and("status", HostIdSearch.entity().getStatus(), SearchCriteria.Op.EQ);
+        HostIdSearch.and("status", HostIdSearch.entity().getState(), SearchCriteria.Op.EQ);
         HostIdSearch.done();
         
         VolumeIdTypeSearch = createSearchBuilder();
@@ -172,7 +166,7 @@
         
         StatusSearch = createSearchBuilder();
         StatusSearch.and("volumeId", StatusSearch.entity().getVolumeId(), SearchCriteria.Op.EQ);
-        StatusSearch.and("status", StatusSearch.entity().getStatus(), SearchCriteria.Op.IN);
+        StatusSearch.and("status", StatusSearch.entity().getState(), SearchCriteria.Op.IN);
         StatusSearch.done();
         
         CountSnapshotsByAccount = createSearchBuilder(Long.class);
@@ -182,7 +176,7 @@
         CountSnapshotsByAccount.done();
         
     	InstanceIdSearch = createSearchBuilder();
-    	InstanceIdSearch.and("status", InstanceIdSearch.entity().getStatus(), SearchCriteria.Op.IN);
+        InstanceIdSearch.and("status", InstanceIdSearch.entity().getState(), SearchCriteria.Op.IN);
     	
     	SearchBuilder<VMInstanceVO> instanceSearch = _instanceDao.createSearchBuilder();
     	instanceSearch.and("instanceId", instanceSearch.entity().getId(), SearchCriteria.Op.EQ);
@@ -274,7 +268,7 @@
     }
     
     @Override
-	public List<SnapshotVO> listByInstanceId(long instanceId, Snapshot.Status... status) {
+	public List<SnapshotVO> listByInstanceId(long instanceId, Snapshot.State... status) {
     	SearchCriteria<SnapshotVO> sc = this.InstanceIdSearch.create();
     	
     	if (status != null && status.length != 0) {
@@ -287,7 +281,7 @@
     }
     
     @Override
-    public List<SnapshotVO> listByStatus(long volumeId, Snapshot.Status... status) {
+    public List<SnapshotVO> listByStatus(long volumeId, Snapshot.State... status) {
     	SearchCriteria<SnapshotVO> sc = this.StatusSearch.create();
     	sc.setParameters("volumeId", volumeId);
     	sc.setParameters("status", (Object[])status);
@@ -309,9 +303,20 @@
     }
     
     @Override
-    public List<SnapshotVO> listAllByStatus(Snapshot.Status... status) {
+    public List<SnapshotVO> listAllByStatus(Snapshot.State... status) {
         SearchCriteria<SnapshotVO> sc = this.StatusSearch.create();
         sc.setParameters("status", (Object[])status);
         return listBy(sc, null);
     }
+
+    @Override
+    public boolean updateState(State currentState, Event event, State nextState, Snapshot snapshot, Object data) {
+        Transaction txn = Transaction.currentTxn();
+        txn.start();
+        SnapshotVO snapshotVO = (SnapshotVO)snapshot;
+        snapshotVO.setStatus(nextState);
+        super.update(snapshotVO.getId(), snapshotVO);
+        txn.commit();
+        return true;
+    }
 }
diff --git a/server/src/com/cloud/storage/download/DownloadMonitorImpl.java b/server/src/com/cloud/storage/download/DownloadMonitorImpl.java
index 2736777..cf51567 100755
--- a/server/src/com/cloud/storage/download/DownloadMonitorImpl.java
+++ b/server/src/com/cloud/storage/download/DownloadMonitorImpl.java
@@ -16,36 +16,14 @@
 // under the License.
 package com.cloud.storage.download;
 
-import java.net.URI;
-import java.net.URISyntaxException;
-import java.util.ArrayList;
-import java.util.Date;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-import java.util.Timer;
-import java.util.concurrent.ConcurrentHashMap;
-
-import javax.ejb.Local;
-
-import org.apache.log4j.Logger;
-
 import com.cloud.agent.AgentManager;
 import com.cloud.agent.Listener;
 import com.cloud.agent.api.Answer;
 import com.cloud.agent.api.Command;
-import com.cloud.agent.api.storage.DeleteTemplateCommand;
-import com.cloud.agent.api.storage.DeleteVolumeCommand;
-import com.cloud.agent.api.storage.DownloadCommand;
-import com.cloud.agent.api.storage.ListVolumeAnswer;
-import com.cloud.agent.api.storage.ListVolumeCommand;
+import com.cloud.agent.api.storage.*;
 import com.cloud.agent.api.storage.DownloadCommand.Proxy;
 import com.cloud.agent.api.storage.DownloadCommand.ResourceType;
-import com.cloud.agent.api.storage.DownloadProgressCommand;
 import com.cloud.agent.api.storage.DownloadProgressCommand.RequestType;
-import com.cloud.agent.api.storage.ListTemplateAnswer;
-import com.cloud.agent.api.storage.ListTemplateCommand;
 import com.cloud.agent.manager.Commands;
 import com.cloud.alert.AlertManager;
 import com.cloud.configuration.Config;
@@ -54,8 +32,7 @@
 import com.cloud.dc.dao.ClusterDao;
 import com.cloud.dc.dao.DataCenterDao;
 import com.cloud.event.EventTypes;
-import com.cloud.event.UsageEventVO;
-import com.cloud.event.dao.UsageEventDao;
+import com.cloud.event.UsageEventUtils;
 import com.cloud.exception.AgentUnavailableException;
 import com.cloud.exception.InvalidParameterValueException;
 import com.cloud.exception.StorageUnavailableException;
@@ -65,26 +42,9 @@
 import com.cloud.hypervisor.Hypervisor.HypervisorType;
 import com.cloud.resource.ResourceManager;
 import com.cloud.storage.Storage.ImageFormat;
-import com.cloud.storage.StorageManager;
-import com.cloud.storage.SwiftVO;
-import com.cloud.storage.VMTemplateHostVO;
-import com.cloud.storage.VMTemplateStorageResourceAssoc;
-import com.cloud.storage.Volume;
-import com.cloud.storage.VolumeHostVO;
-import com.cloud.storage.VolumeVO;
+import com.cloud.storage.*;
 import com.cloud.storage.VMTemplateStorageResourceAssoc.Status;
-import com.cloud.storage.Volume.Event;
-import com.cloud.storage.VMTemplateVO;
-import com.cloud.storage.VMTemplateZoneVO;
-import com.cloud.storage.dao.StoragePoolHostDao;
-import com.cloud.storage.dao.SwiftDao;
-import com.cloud.storage.dao.VMTemplateDao;
-import com.cloud.storage.dao.VMTemplateHostDao;
-import com.cloud.storage.dao.VMTemplatePoolDao;
-import com.cloud.storage.dao.VMTemplateSwiftDao;
-import com.cloud.storage.dao.VMTemplateZoneDao;
-import com.cloud.storage.dao.VolumeDao;
-import com.cloud.storage.dao.VolumeHostDao;
+import com.cloud.storage.dao.*;
 import com.cloud.storage.secondary.SecondaryStorageVmManager;
 import com.cloud.storage.swift.SwiftManager;
 import com.cloud.storage.template.TemplateConstants;
@@ -92,19 +52,21 @@
 import com.cloud.user.Account;
 import com.cloud.user.ResourceLimitService;
 import com.cloud.utils.component.Inject;
-import com.cloud.utils.db.DB;
-import com.cloud.utils.db.JoinBuilder;
-import com.cloud.utils.db.SearchBuilder;
-import com.cloud.utils.db.SearchCriteria;
-import com.cloud.utils.db.Transaction;
+import com.cloud.utils.db.*;
 import com.cloud.utils.exception.CloudRuntimeException;
-import com.cloud.utils.fsm.NoTransitionException;
 import com.cloud.vm.SecondaryStorageVm;
 import com.cloud.vm.SecondaryStorageVmVO;
 import com.cloud.vm.UserVmManager;
 import com.cloud.vm.VirtualMachine.State;
 import com.cloud.vm.dao.SecondaryStorageVmDao;
 import edu.emory.mathcs.backport.java.util.Collections;
+import org.apache.log4j.Logger;
+
+import javax.ejb.Local;
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.util.*;
+import java.util.concurrent.ConcurrentHashMap;
 
 
 @Local(value={DownloadMonitor.class})
@@ -147,11 +109,6 @@
     ConfigurationDao _configDao;
     @Inject
     UserVmManager _vmMgr;
-
-    
-    @Inject 
-    private UsageEventDao _usageEventDao;
-    
     @Inject
     private ClusterDao _clusterDao;
     @Inject
@@ -517,8 +474,9 @@
                 eventType = EventTypes.EVENT_ISO_CREATE;
             }
             if(template.getAccountId() != Account.ACCOUNT_ID_SYSTEM){
-                UsageEventVO usageEvent = new UsageEventVO(eventType, template.getAccountId(), host.getDataCenterId(), template.getId(), template.getName(), null, template.getSourceTemplateId() , size);
-                _usageEventDao.persist(usageEvent);
+                UsageEventUtils.publishUsageEvent(eventType, template.getAccountId(), host.getDataCenterId(),
+                        template.getId(), template.getName(), null, template.getSourceTemplateId(), size,
+                        template.getClass().getName(), template.getUuid());
             }
         }
         txn.commit();
@@ -550,8 +508,8 @@
             }
             String eventType = EventTypes.EVENT_VOLUME_UPLOAD;            
             if(volume.getAccountId() != Account.ACCOUNT_ID_SYSTEM){
-               UsageEventVO usageEvent = new UsageEventVO(eventType, volume.getAccountId(), host.getDataCenterId(), volume.getId(), volume.getName(), null, 0l , size);
-               _usageEventDao.persist(usageEvent);
+                UsageEventUtils.publishUsageEvent(eventType, volume.getAccountId(), host.getDataCenterId(),
+                        volume.getId(), volume.getName(), null, 0l, size, volume.getClass().getName(), volume.getUuid());
             }
         }else if (dnldStatus == Status.DOWNLOAD_ERROR || dnldStatus == Status.ABANDONED || dnldStatus == Status.UNKNOWN){
             //Decrement the volume count
diff --git a/server/src/com/cloud/storage/listener/SnapshotStateListener.java b/server/src/com/cloud/storage/listener/SnapshotStateListener.java
new file mode 100644
index 0000000..2b19887
--- /dev/null
+++ b/server/src/com/cloud/storage/listener/SnapshotStateListener.java
@@ -0,0 +1,85 @@
+package com.cloud.storage.listener;
+
+import com.cloud.event.EventCategory;
+import com.cloud.storage.Snapshot;
+import com.cloud.storage.Snapshot.Event;
+import com.cloud.storage.Snapshot.State;
+import com.cloud.server.ManagementServer;
+import com.cloud.utils.component.Adapters;
+import com.cloud.utils.component.ComponentLocator;
+import com.cloud.utils.fsm.StateListener;
+import org.apache.cloudstack.framework.events.EventBus;
+import org.apache.cloudstack.framework.events.EventBusException;
+import org.apache.log4j.Logger;
+
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.Map;
+
+public class SnapshotStateListener implements StateListener<State, Event, Snapshot> {
+
+    // get the event bus provider if configured
+    protected static EventBus _eventBus = null;
+    static {
+        Adapters<EventBus> eventBusImpls = ComponentLocator.getLocator(ManagementServer.Name).getAdapters(EventBus.class);
+        if (eventBusImpls != null) {
+            Enumeration<EventBus> eventBusenum = eventBusImpls.enumeration();
+            if (eventBusenum != null && eventBusenum.hasMoreElements()) {
+                _eventBus = eventBusenum.nextElement(); // configure event bus if configured
+            }
+        }
+    }
+
+    private static final Logger s_logger = Logger.getLogger(VolumeStateListener.class);
+
+    public SnapshotStateListener() {
+
+    }
+
+    @Override
+    public boolean preStateTransitionEvent(State oldState, Event event, State newState, Snapshot vo, boolean status, Object opaque) {
+        pubishOnEventBus(event.name(), "preStateTransitionEvent", vo, oldState, newState);
+        return true;
+    }
+
+    @Override
+    public boolean postStateTransitionEvent(State oldState, Event event, State newState, Snapshot vo, boolean status, Object opaque) {
+        pubishOnEventBus(event.name(), "postStateTransitionEvent", vo, oldState, newState);
+        return true;
+    }
+
+    private void pubishOnEventBus(String event, String status, Snapshot vo, State oldState, State newState) {
+
+        if (_eventBus == null) {
+            return;  // no provider is configured to provide events bus, so just return
+        }
+
+        String resourceName = getEntityFromClassName(Snapshot.class.getName());
+        org.apache.cloudstack.framework.events.Event eventMsg =  new org.apache.cloudstack.framework.events.Event(
+                ManagementServer.Name,
+                EventCategory.RESOURCE_STATE_CHANGE_EVENT.getName(),
+                event,
+                resourceName,
+                vo.getUuid());
+        Map<String, String> eventDescription = new HashMap<String, String>();
+        eventDescription.put("resource", resourceName);
+        eventDescription.put("id", vo.getUuid());
+        eventDescription.put("old-state", oldState.name());
+        eventDescription.put("new-state", newState.name());
+        eventMsg.setDescription(eventDescription);
+        try {
+            _eventBus.publish(eventMsg);
+        } catch (EventBusException e) {
+            s_logger.warn("Failed to publish state change event on the the event bus.");
+        }
+    }
+
+    private String getEntityFromClassName(String entityClassName) {
+        int index = entityClassName.lastIndexOf(".");
+        String entityName = entityClassName;
+        if (index != -1) {
+            entityName = entityClassName.substring(index+1);
+        }
+        return entityName;
+    }
+}
diff --git a/server/src/com/cloud/storage/listener/VolumeStateListener.java b/server/src/com/cloud/storage/listener/VolumeStateListener.java
new file mode 100644
index 0000000..c460016
--- /dev/null
+++ b/server/src/com/cloud/storage/listener/VolumeStateListener.java
@@ -0,0 +1,85 @@
+package com.cloud.storage.listener;
+
+import com.cloud.event.EventCategory;
+import com.cloud.storage.Volume;
+import com.cloud.storage.Volume.Event;
+import com.cloud.storage.Volume.State;
+import com.cloud.server.ManagementServer;
+import com.cloud.utils.component.Adapters;
+import com.cloud.utils.component.ComponentLocator;
+import com.cloud.utils.fsm.StateListener;
+import org.apache.cloudstack.framework.events.EventBus;
+import org.apache.cloudstack.framework.events.EventBusException;
+import org.apache.log4j.Logger;
+
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.Map;
+
+public class VolumeStateListener implements StateListener<State, Event, Volume> {
+
+    // get the event bus provider if configured
+    protected static EventBus _eventBus = null;
+    static {
+        Adapters<EventBus> eventBusImpls = ComponentLocator.getLocator(ManagementServer.Name).getAdapters(EventBus.class);
+        if (eventBusImpls != null) {
+            Enumeration<EventBus> eventBusenum = eventBusImpls.enumeration();
+            if (eventBusenum != null && eventBusenum.hasMoreElements()) {
+                _eventBus = eventBusenum.nextElement(); // configure event bus if configured
+            }
+        }
+    }
+
+    private static final Logger s_logger = Logger.getLogger(VolumeStateListener.class);
+
+    public VolumeStateListener() {
+
+    }
+
+    @Override
+    public boolean preStateTransitionEvent(State oldState, Event event, State newState, Volume vo, boolean status, Object opaque) {
+        pubishOnEventBus(event.name(), "preStateTransitionEvent", vo, oldState, newState);
+        return true;
+    }
+
+    @Override
+    public boolean postStateTransitionEvent(State oldState, Event event, State newState, Volume vo, boolean status, Object opaque) {
+        pubishOnEventBus(event.name(), "postStateTransitionEvent", vo, oldState, newState);
+        return true;
+    }
+
+    private void pubishOnEventBus(String event, String status, Volume vo, State oldState, State newState) {
+
+        if (_eventBus == null) {
+            return;  // no provider is configured to provide events bus, so just return
+        }
+
+        String resourceName = getEntityFromClassName(Volume.class.getName());
+        org.apache.cloudstack.framework.events.Event eventMsg =  new org.apache.cloudstack.framework.events.Event(
+                ManagementServer.Name,
+                EventCategory.RESOURCE_STATE_CHANGE_EVENT.getName(),
+                event,
+                resourceName,
+                vo.getUuid());
+        Map<String, String> eventDescription = new HashMap<String, String>();
+        eventDescription.put("resource", resourceName);
+        eventDescription.put("id", vo.getUuid());
+        eventDescription.put("old-state", oldState.name());
+        eventDescription.put("new-state", newState.name());
+        eventMsg.setDescription(eventDescription);
+        try {
+            _eventBus.publish(eventMsg);
+        } catch (EventBusException e) {
+            s_logger.warn("Failed to state change event on the the event bus.");
+        }
+    }
+
+    private String getEntityFromClassName(String entityClassName) {
+        int index = entityClassName.lastIndexOf(".");
+        String entityName = entityClassName;
+        if (index != -1) {
+            entityName = entityClassName.substring(index+1);
+        }
+        return entityName;
+    }
+}
diff --git a/server/src/com/cloud/storage/snapshot/SnapshotManagerImpl.java b/server/src/com/cloud/storage/snapshot/SnapshotManagerImpl.java
index 15d8c53..66eb8e1 100755
--- a/server/src/com/cloud/storage/snapshot/SnapshotManagerImpl.java
+++ b/server/src/com/cloud/storage/snapshot/SnapshotManagerImpl.java
@@ -16,37 +16,12 @@
 // under the License.
 package com.cloud.storage.snapshot;
 
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.Date;
-import java.util.List;
-import java.util.Map;
-import java.util.TimeZone;
-
-import javax.ejb.Local;
-import javax.naming.ConfigurationException;
-
-import org.apache.cloudstack.api.command.user.snapshot.CreateSnapshotPolicyCmd;
-import org.apache.cloudstack.api.command.user.snapshot.ListSnapshotsCmd;
-import org.apache.log4j.Logger;
-
 import com.cloud.agent.AgentManager;
-import com.cloud.agent.api.Answer;
-import com.cloud.agent.api.BackupSnapshotAnswer;
-import com.cloud.agent.api.BackupSnapshotCommand;
-import com.cloud.agent.api.Command;
-import com.cloud.agent.api.DeleteSnapshotBackupCommand;
-import com.cloud.agent.api.DeleteSnapshotsDirCommand;
-import com.cloud.agent.api.DownloadSnapshotFromS3Command;
-import com.cloud.agent.api.ManageSnapshotAnswer;
-import com.cloud.agent.api.ManageSnapshotCommand;
-import com.cloud.agent.api.downloadSnapshotFromSwiftCommand;
+import com.cloud.agent.api.*;
 import com.cloud.agent.api.to.S3TO;
 import com.cloud.agent.api.to.SwiftTO;
 import com.cloud.alert.AlertManager;
-import org.apache.cloudstack.api.command.user.snapshot.DeleteSnapshotPoliciesCmd;
 import com.cloud.api.commands.ListRecurringSnapshotScheduleCmd;
-import org.apache.cloudstack.api.command.user.snapshot.ListSnapshotPoliciesCmd;
 import com.cloud.configuration.Config;
 import com.cloud.configuration.Resource.ResourceType;
 import com.cloud.configuration.dao.ConfigurationDao;
@@ -55,11 +30,7 @@
 import com.cloud.dc.dao.ClusterDao;
 import com.cloud.dc.dao.DataCenterDao;
 import com.cloud.domain.dao.DomainDao;
-import com.cloud.event.ActionEvent;
-import com.cloud.event.EventTypes;
-import com.cloud.event.EventUtils;
-import com.cloud.event.EventVO;
-import com.cloud.event.UsageEventVO;
+import com.cloud.event.*;
 import com.cloud.event.dao.EventDao;
 import com.cloud.event.dao.UsageEventDao;
 import com.cloud.exception.InvalidParameterValueException;
@@ -69,44 +40,21 @@
 import com.cloud.host.HostVO;
 import com.cloud.host.dao.HostDao;
 import com.cloud.hypervisor.Hypervisor.HypervisorType;
-import com.cloud.network.PhysicalNetworkTrafficType;
 import com.cloud.org.Grouping;
 import com.cloud.projects.Project.ListProjectResourcesCriteria;
 import com.cloud.resource.ResourceManager;
 import com.cloud.server.ResourceTag.TaggedResourceType;
-import com.cloud.storage.Snapshot;
-import com.cloud.storage.Snapshot.Status;
+import com.cloud.storage.*;
 import com.cloud.storage.Snapshot.Type;
-import com.cloud.storage.SnapshotPolicyVO;
-import com.cloud.storage.SnapshotScheduleVO;
-import com.cloud.storage.SnapshotVO;
-import com.cloud.storage.Storage;
 import com.cloud.storage.Storage.StoragePoolType;
-import com.cloud.storage.StorageManager;
-import com.cloud.storage.StoragePool;
-import com.cloud.storage.StoragePoolVO;
-import com.cloud.storage.VMTemplateVO;
-import com.cloud.storage.Volume;
-import com.cloud.storage.VolumeVO;
-import com.cloud.storage.dao.DiskOfferingDao;
-import com.cloud.storage.dao.SnapshotDao;
-import com.cloud.storage.dao.SnapshotPolicyDao;
-import com.cloud.storage.dao.SnapshotScheduleDao;
-import com.cloud.storage.dao.StoragePoolDao;
-import com.cloud.storage.dao.VMTemplateDao;
-import com.cloud.storage.dao.VolumeDao;
+import com.cloud.storage.dao.*;
+import com.cloud.storage.listener.SnapshotStateListener;
 import com.cloud.storage.s3.S3Manager;
 import com.cloud.storage.secondary.SecondaryStorageVmManager;
 import com.cloud.storage.swift.SwiftManager;
 import com.cloud.tags.ResourceTagVO;
 import com.cloud.tags.dao.ResourceTagDao;
-import com.cloud.user.Account;
-import com.cloud.user.AccountManager;
-import com.cloud.user.AccountVO;
-import com.cloud.user.DomainManager;
-import com.cloud.user.ResourceLimitService;
-import com.cloud.user.User;
-import com.cloud.user.UserContext;
+import com.cloud.user.*;
 import com.cloud.user.dao.AccountDao;
 import com.cloud.utils.DateUtil;
 import com.cloud.utils.DateUtil.IntervalType;
@@ -116,18 +64,24 @@
 import com.cloud.utils.component.ComponentLocator;
 import com.cloud.utils.component.Inject;
 import com.cloud.utils.component.Manager;
-import com.cloud.utils.db.DB;
-import com.cloud.utils.db.Filter;
-import com.cloud.utils.db.JoinBuilder;
-import com.cloud.utils.db.SearchBuilder;
-import com.cloud.utils.db.SearchCriteria;
-import com.cloud.utils.db.Transaction;
+import com.cloud.utils.db.*;
 import com.cloud.utils.exception.CloudRuntimeException;
+import com.cloud.utils.fsm.NoTransitionException;
+import com.cloud.utils.fsm.StateMachine2;
 import com.cloud.vm.UserVmVO;
 import com.cloud.vm.VMInstanceVO;
 import com.cloud.vm.VirtualMachine;
 import com.cloud.vm.VirtualMachine.State;
 import com.cloud.vm.dao.UserVmDao;
+import org.apache.cloudstack.api.command.user.snapshot.CreateSnapshotPolicyCmd;
+import org.apache.cloudstack.api.command.user.snapshot.DeleteSnapshotPoliciesCmd;
+import org.apache.cloudstack.api.command.user.snapshot.ListSnapshotPoliciesCmd;
+import org.apache.cloudstack.api.command.user.snapshot.ListSnapshotsCmd;
+import org.apache.log4j.Logger;
+
+import javax.ejb.Local;
+import javax.naming.ConfigurationException;
+import java.util.*;
 
 @Local(value = { SnapshotManager.class, SnapshotService.class })
 public class SnapshotManagerImpl implements SnapshotManager, SnapshotService, Manager {
@@ -195,6 +149,8 @@
     private int _deltaSnapshotMax;
     private int _backupsnapshotwait;
 
+    private StateMachine2<Snapshot.State, Snapshot.Event, Snapshot> _snapshotFsm;
+
     protected SearchBuilder<SnapshotVO> PolicySnapshotSearch;
     protected SearchBuilder<SnapshotPolicyVO> PoliciesForSnapSearch;
 
@@ -259,6 +215,13 @@
         if (snapshot == null) {
             throw new CloudRuntimeException("Can not find snapshot " + snapshotId);
         }
+
+        try {
+            stateTransitTo(snapshot, Snapshot.Event.CreateRequested);
+        } catch (NoTransitionException nte) {
+            s_logger.debug("Failed to update snapshot state due to " + nte.getMessage());
+        }
+
         // Send a ManageSnapshotCommand to the agent
         String vmName = _storageMgr.getVmNameOnVolume(volume);
         long volumeId = volume.getId();
@@ -289,14 +252,16 @@
             if (preSnapshotPath != null && preSnapshotPath.equals(answer.getSnapshotPath())) {
                 // empty snapshot
                 s_logger.debug("CreateSnapshot: this is empty snapshot ");
-                snapshot.setPath(preSnapshotPath);
-                snapshot.setBackupSnapshotId(preSnapshotVO.getBackupSnapshotId());
-                snapshot.setSwiftId(preSnapshotVO.getSwiftId());
-
-                snapshot.setStatus(Snapshot.Status.BackedUp);
-                snapshot.setPrevSnapshotId(preId);
-                snapshot.setSecHostId(preSnapshotVO.getSecHostId());
-                _snapshotDao.update(snapshotId, snapshot);
+                try {
+                    snapshot.setPath(preSnapshotPath);
+                    snapshot.setBackupSnapshotId(preSnapshotVO.getBackupSnapshotId());
+                    snapshot.setSwiftId(preSnapshotVO.getSwiftId());
+                    snapshot.setPrevSnapshotId(preId);
+                    snapshot.setSecHostId(preSnapshotVO.getSecHostId());
+                    stateTransitTo(snapshot, Snapshot.Event.OperationNotPerformed);
+                }  catch (NoTransitionException nte) {
+                    s_logger.debug("CreateSnapshot: failed to update state of snapshot due to " + nte.getMessage());
+                }
             } else {
                 long preSnapshotId = 0;
 
@@ -346,6 +311,11 @@
             if (answer != null) {
                 s_logger.error(answer.getDetails());
             }
+            try {
+                stateTransitTo(snapshot, Snapshot.Event.OperationFailed);
+            } catch (NoTransitionException nte) {
+                s_logger.debug("Failed to update snapshot state due to " + nte.getMessage());
+            }
             throw new CloudRuntimeException("Creating snapshot for volume " + volumeId + " on primary storage failed.");
         }
 
@@ -410,7 +380,7 @@
                     }
 
                     if(userVm.getHypervisorType() == HypervisorType.VMware || userVm.getHypervisorType() == HypervisorType.KVM) {
-                        List<SnapshotVO> activeSnapshots = _snapshotDao.listByInstanceId(volume.getInstanceId(), Snapshot.Status.Creating,  Snapshot.Status.CreatedOnPrimary,  Snapshot.Status.BackingUp);
+                        List<SnapshotVO> activeSnapshots = _snapshotDao.listByInstanceId(volume.getInstanceId(), Snapshot.State.Creating,  Snapshot.State.CreatedOnPrimary,  Snapshot.State.BackingUp);
                         if(activeSnapshots.size() > 1)
                             throw new CloudRuntimeException("There is other active snapshot tasks on the instance to which the volume is attached, please try again later");
                     }
@@ -419,19 +389,15 @@
 
             snapshot = createSnapshotOnPrimary(volume, policyId, snapshotId);
             if (snapshot != null) {
-                if (snapshot.getStatus() == Snapshot.Status.CreatedOnPrimary) {
+                if (snapshot.getState() == Snapshot.State.CreatedOnPrimary) {
                     backedUp = backupSnapshotToSecondaryStorage(snapshot);
-                } else if (snapshot.getStatus() == Snapshot.Status.BackedUp) {
+                } else if (snapshot.getState() == Snapshot.State.BackedUp) {
                     // For empty snapshot we set status to BackedUp in createSnapshotOnPrimary
                     backedUp = true;
                 } else {
-                    snapshot.setStatus(Status.Error);
-                    _snapshotDao.update(snapshot.getId(), snapshot);
                     throw new CloudRuntimeException("Failed to create snapshot: " + snapshot + " on primary storage");
                 }
                 if (!backedUp) {
-                    snapshot.setStatus(Status.Error);
-                    _snapshotDao.update(snapshot.getId(), snapshot);
                     throw new CloudRuntimeException("Created snapshot: " + snapshot + " on primary but failed to backup on secondary");
                 }
             } else {
@@ -444,23 +410,15 @@
                 //Check if the snapshot was removed while backingUp. If yes, do not log snapshot create usage event
                 SnapshotVO freshSnapshot = _snapshotDao.findById(snapshot.getId());
                 if ((freshSnapshot != null) && backedUp) {
-                    UsageEventVO usageEvent = new UsageEventVO(EventTypes.EVENT_SNAPSHOT_CREATE, snapshot.getAccountId(), snapshot.getDataCenterId(), snapshotId, snapshot.getName(), null, null,
-                            volume.getSize());
-                    _usageEventDao.persist(usageEvent);
+                    UsageEventUtils.publishUsageEvent(EventTypes.EVENT_SNAPSHOT_CREATE, snapshot.getAccountId(),
+                            snapshot.getDataCenterId(), snapshotId, snapshot.getName(), null, null,
+                            volume.getSize(), snapshot.getClass().getName(), snapshot.getUuid());
                 }
                 if( !backedUp ) {
 
-                    snapshot.setStatus(Status.Error);
-                    _snapshotDao.update(snapshot.getId(), snapshot);
                 } else {
                     _resourceLimitMgr.incrementResourceCount(snapshotOwner.getId(), ResourceType.snapshot);
                 }
-            } else {
-            	snapshot = _snapshotDao.findById(snapshotId);
-            	if (snapshot != null) {
-            		snapshot.setStatus(Status.Error);
-            		_snapshotDao.update(snapshotId, snapshot);
-            	}
             }
 
             /*
@@ -478,9 +436,12 @@
     private SnapshotVO updateDBOnCreate(Long id, String snapshotPath, long preSnapshotId) {
         SnapshotVO createdSnapshot = _snapshotDao.findByIdIncludingRemoved(id);
         createdSnapshot.setPath(snapshotPath);
-        createdSnapshot.setStatus(Snapshot.Status.CreatedOnPrimary);
         createdSnapshot.setPrevSnapshotId(preSnapshotId);
-        _snapshotDao.update(id, createdSnapshot);
+        try {
+            stateTransitTo(createdSnapshot, Snapshot.Event.OperationSucceeded);
+        } catch (NoTransitionException nte) {
+            s_logger.debug("Faile to update state of snapshot due to " + nte.getMessage());
+        }
         return createdSnapshot;
     }
 
@@ -622,9 +583,11 @@
             throw new CloudRuntimeException("Can not acquire lock for snapshot: " + ss);
         }
         try {
-
-            snapshot.setStatus(Snapshot.Status.BackingUp);
-            _snapshotDao.update(snapshot.getId(), snapshot);
+            try {
+                stateTransitTo(snapshot, Snapshot.Event.BackupToSecondary);
+            } catch (NoTransitionException nte) {
+                s_logger.debug("Failed to update the state of snapshot while backing up snapshot");
+            }
 
             long volumeId = snapshot.getVolumeId();
             VolumeVO volume = _volsDao.lockRow(volumeId, true);
@@ -705,10 +668,18 @@
                 if (answer.isFull()) {
                     snapshot.setPrevSnapshotId(0);
                 }
-                snapshot.setStatus(Snapshot.Status.BackedUp);
-                _snapshotDao.update(snapshotId, snapshot);
+                try {
+                    stateTransitTo(snapshot, Snapshot.Event.OperationSucceeded);
+                } catch (NoTransitionException nte) {
+                    s_logger.debug("Failed to update the state of snapshot while backing up snapshot");
+                }
 
             } else {
+                try {
+                    stateTransitTo(snapshot, Snapshot.Event.OperationFailed);
+                } catch (NoTransitionException nte) {
+                    s_logger.debug("Failed to update the state of snapshot while backing up snapshot");
+                }
                 s_logger.warn("Failed to back up snapshot on secondary storage, deleting the record from the DB");
                 _snapshotDao.remove(snapshotId);
             }
@@ -766,8 +737,8 @@
             long oldSnapId = oldestSnapshot.getId();
             s_logger.debug("Max snaps: " + policy.getMaxSnaps() + " exceeded for snapshot policy with Id: " + policyId + ". Deleting oldest snapshot: " + oldSnapId);
             if(deleteSnapshotInternal(oldSnapId)){
-            	//log Snapshot delete event
-            	EventUtils.saveEvent(User.UID_SYSTEM, oldestSnapshot.getAccountId(), EventVO.LEVEL_INFO, EventTypes.EVENT_SNAPSHOT_DELETE, "Successfully deleted oldest snapshot: " + oldSnapId, 0);
+                //log Snapshot delete event
+                ActionEventUtils.onCompletedActionEvent(User.UID_SYSTEM, oldestSnapshot.getAccountId(), EventVO.LEVEL_INFO, EventTypes.EVENT_SNAPSHOT_DELETE, "Successfully deleted oldest snapshot: " + oldSnapId, 0);
             }
             snaps.remove(oldestSnapshot);
         }
@@ -787,7 +758,7 @@
 
         _accountMgr.checkAccess(caller, null, true, snapshotCheck);
 
-        if( !Status.BackedUp.equals(snapshotCheck.getStatus() ) ) {
+        if( !Snapshot.State.BackedUp.equals(snapshotCheck.getState() ) ) {
             throw new InvalidParameterValueException("Can't delete snapshotshot " + snapshotId + " due to it is not in BackedUp Status");
         }
 
@@ -812,9 +783,10 @@
         Transaction txn = Transaction.currentTxn();
         txn.start();
         _snapshotDao.remove(snapshotId);
-        if (snapshot.getStatus() == Snapshot.Status.BackedUp) {
-        	UsageEventVO usageEvent = new UsageEventVO(EventTypes.EVENT_SNAPSHOT_DELETE, snapshot.getAccountId(), snapshot.getDataCenterId(), snapshotId, snapshot.getName(), null, null, 0L);
-        	_usageEventDao.persist(usageEvent);
+        if (snapshot.getState() == Snapshot.State.BackedUp) {
+            UsageEventUtils.publishUsageEvent(EventTypes.EVENT_SNAPSHOT_DELETE, snapshot.getAccountId(),
+                    snapshot.getDataCenterId(), snapshotId, snapshot.getName(), null, null, 0L,
+                    snapshot.getClass().getName(), snapshot.getUuid());
         }
         _resourceLimitMgr.decrementResourceCount(snapshot.getAccountId(), ResourceType.snapshot);
         txn.commit();
@@ -966,7 +938,7 @@
         SearchBuilder<SnapshotVO> sb = _snapshotDao.createSearchBuilder();
         _accountMgr.buildACLSearchBuilder(sb, domainId, isRecursive, permittedAccounts, listProjectResourcesCriteria);
 
-        sb.and("status", sb.entity().getStatus(), SearchCriteria.Op.EQ);
+        sb.and("status", sb.entity().getState(), SearchCriteria.Op.EQ);
         sb.and("volumeId", sb.entity().getVolumeId(), SearchCriteria.Op.EQ);
         sb.and("name", sb.entity().getName(), SearchCriteria.Op.LIKE);
         sb.and("id", sb.entity().getId(), SearchCriteria.Op.EQ);
@@ -1115,9 +1087,9 @@
                     }
 
                     // Log event after successful deletion
-                    UsageEventVO usageEvent = new UsageEventVO(EventTypes.EVENT_SNAPSHOT_DELETE, snapshot.getAccountId(), volume.getDataCenterId(), snapshot.getId(), snapshot.getName(), null, null,
-                            volume.getSize());
-                    _usageEventDao.persist(usageEvent);
+                    UsageEventUtils.publishUsageEvent(EventTypes.EVENT_SNAPSHOT_DELETE, snapshot.getAccountId(),
+                            volume.getDataCenterId(), snapshot.getId(), snapshot.getName(), null, null,
+                            volume.getSize(), snapshot.getClass().getName(), snapshot.getUuid());
                 }
             }
         }
@@ -1452,6 +1424,9 @@
 
         s_logger.info("Snapshot Manager is configured.");
 
+        _snapshotFsm = Snapshot.State.getStateMachine();
+        _snapshotFsm.registerListener(new SnapshotStateListener());
+
         return true;
     }
 
@@ -1538,11 +1513,15 @@
 
     @Override
     public boolean canOperateOnVolume(VolumeVO volume) {
-    	List<SnapshotVO> snapshots = _snapshotDao.listByStatus(volume.getId(), Status.Creating, Status.CreatedOnPrimary, Status.BackingUp);
+        List<SnapshotVO> snapshots = _snapshotDao.listByStatus(volume.getId(), Snapshot.State.Creating,
+                Snapshot.State.CreatedOnPrimary, Snapshot.State.BackingUp);
     	if (snapshots.size() > 0) {
     		return false;
     	}
     	return true;
     }
 
+    protected boolean stateTransitTo(Snapshot snapshot, Snapshot.Event e) throws NoTransitionException {
+        return _snapshotFsm.transitTo(snapshot, e, null, _snapshotDao);
+    }
 }
diff --git a/server/src/com/cloud/storage/snapshot/SnapshotSchedulerImpl.java b/server/src/com/cloud/storage/snapshot/SnapshotSchedulerImpl.java
index d7deb6f..9389893 100644
--- a/server/src/com/cloud/storage/snapshot/SnapshotSchedulerImpl.java
+++ b/server/src/com/cloud/storage/snapshot/SnapshotSchedulerImpl.java
@@ -26,6 +26,7 @@
 import javax.ejb.Local;
 import javax.naming.ConfigurationException;
 
+import com.cloud.event.ActionEventUtils;
 import org.apache.cloudstack.api.command.user.snapshot.CreateSnapshotCmd;
 import org.apache.log4j.Logger;
 
@@ -39,7 +40,6 @@
 import com.cloud.async.dao.AsyncJobDao;
 import com.cloud.configuration.dao.ConfigurationDao;
 import com.cloud.event.EventTypes;
-import com.cloud.event.EventUtils;
 import com.cloud.storage.Snapshot;
 import com.cloud.storage.SnapshotPolicyVO;
 import com.cloud.storage.SnapshotScheduleVO;
@@ -232,8 +232,8 @@
 
 
                 tmpSnapshotScheduleVO = _snapshotScheduleDao.acquireInLockTable(snapshotScheId);
-                Long eventId = EventUtils.saveScheduledEvent(User.UID_SYSTEM, Account.ACCOUNT_ID_SYSTEM,
-                        EventTypes.EVENT_SNAPSHOT_CREATE, "creating snapshot for volume Id:"+volumeId,0);
+                Long eventId = ActionEventUtils.onScheduledActionEvent(User.UID_SYSTEM, Account.ACCOUNT_ID_SYSTEM,
+                        EventTypes.EVENT_SNAPSHOT_CREATE, "creating snapshot for volume Id:" + volumeId, 0);
 
                 Map<String, String> params = new HashMap<String, String>();
                 params.put(ApiConstants.VOLUME_ID, "" + volumeId);
diff --git a/server/src/com/cloud/template/HyervisorTemplateAdapter.java b/server/src/com/cloud/template/HyervisorTemplateAdapter.java
index c80d1de..81a482b 100755
--- a/server/src/com/cloud/template/HyervisorTemplateAdapter.java
+++ b/server/src/com/cloud/template/HyervisorTemplateAdapter.java
@@ -16,28 +16,13 @@
 // under the License.
 package com.cloud.template;
 
-import java.net.Inet6Address;
-import java.net.InetAddress;
-import java.net.URI;
-import java.net.URISyntaxException;
-import java.net.UnknownHostException;
-import java.util.List;
-
-import javax.ejb.Local;
-
-import org.apache.cloudstack.api.command.user.iso.DeleteIsoCmd;
-import org.apache.cloudstack.api.command.user.iso.RegisterIsoCmd;
-import org.apache.log4j.Logger;
-
 import com.cloud.agent.AgentManager;
 import com.cloud.agent.api.Answer;
 import com.cloud.agent.api.storage.DeleteTemplateCommand;
-import org.apache.cloudstack.api.command.user.template.DeleteTemplateCmd;
-import org.apache.cloudstack.api.command.user.template.RegisterTemplateCmd;
 import com.cloud.configuration.Resource.ResourceType;
 import com.cloud.dc.DataCenterVO;
 import com.cloud.event.EventTypes;
-import com.cloud.event.UsageEventVO;
+import com.cloud.event.UsageEventUtils;
 import com.cloud.exception.InvalidParameterValueException;
 import com.cloud.exception.ResourceAllocationException;
 import com.cloud.host.HostVO;
@@ -53,6 +38,15 @@
 import com.cloud.utils.component.Inject;
 import com.cloud.utils.db.DB;
 import com.cloud.utils.exception.CloudRuntimeException;
+import org.apache.cloudstack.api.command.user.iso.DeleteIsoCmd;
+import org.apache.cloudstack.api.command.user.iso.RegisterIsoCmd;
+import org.apache.cloudstack.api.command.user.template.DeleteTemplateCmd;
+import org.apache.cloudstack.api.command.user.template.RegisterTemplateCmd;
+import org.apache.log4j.Logger;
+
+import javax.ejb.Local;
+import java.net.*;
+import java.util.List;
 
 @Local(value=TemplateAdapter.class)
 public class HyervisorTemplateAdapter extends TemplateAdapterBase implements TemplateAdapter {
@@ -202,8 +196,7 @@
 						success = false;
 						break;
 					}
-					UsageEventVO usageEvent = new UsageEventVO(eventType, account.getId(), sZoneId, templateId, null);
-					_usageEventDao.persist(usageEvent);					
+					UsageEventUtils.publishUsageEvent(eventType, account.getId(), sZoneId, templateId, null, null, null);
                     templateHostVO.setDestroyed(true);
 					_tmpltHostDao.update(templateHostVO.getId(), templateHostVO);
                     String installPath = templateHostVO.getInstallPath();
diff --git a/server/src/com/cloud/template/TemplateManagerImpl.java b/server/src/com/cloud/template/TemplateManagerImpl.java
index 1372111..42106b3 100755
--- a/server/src/com/cloud/template/TemplateManagerImpl.java
+++ b/server/src/com/cloud/template/TemplateManagerImpl.java
@@ -16,41 +16,14 @@
 // under the License.
 package com.cloud.template;
 
-import java.net.Inet6Address;
-import java.net.InetAddress;
-import java.net.URI;
-import java.net.URISyntaxException;
-import java.net.UnknownHostException;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.Date;
-import java.util.List;
-import java.util.Map;
-import java.util.concurrent.ExecutorService;
-import java.util.concurrent.Executors;
-import java.util.concurrent.ScheduledExecutorService;
-import java.util.concurrent.TimeUnit;
-
-import javax.ejb.Local;
-import javax.naming.ConfigurationException;
-
-import org.apache.cloudstack.api.BaseListTemplateOrIsoPermissionsCmd;
-import org.apache.cloudstack.api.BaseUpdateTemplateOrIsoPermissionsCmd;
-import org.apache.cloudstack.api.command.user.iso.*;
-import org.apache.cloudstack.api.command.user.template.*;
-import org.apache.log4j.Logger;
-
-import org.apache.cloudstack.acl.SecurityChecker.AccessType;
 import com.cloud.agent.AgentManager;
 import com.cloud.agent.api.Answer;
 import com.cloud.agent.api.downloadTemplateFromSwiftToSecondaryStorageCommand;
-import com.cloud.agent.api.uploadTemplateToSwiftFromSecondaryStorageCommand;
 import com.cloud.agent.api.storage.DestroyCommand;
 import com.cloud.agent.api.storage.PrimaryStorageDownloadAnswer;
 import com.cloud.agent.api.storage.PrimaryStorageDownloadCommand;
 import com.cloud.agent.api.to.SwiftTO;
-import org.apache.cloudstack.api.command.user.iso.RegisterIsoCmd;
-import org.apache.cloudstack.api.command.user.template.RegisterTemplateCmd;
+import com.cloud.agent.api.uploadTemplateToSwiftFromSecondaryStorageCommand;
 import com.cloud.async.AsyncJobManager;
 import com.cloud.async.AsyncJobVO;
 import com.cloud.configuration.Config;
@@ -63,7 +36,7 @@
 import com.cloud.domain.dao.DomainDao;
 import com.cloud.event.ActionEvent;
 import com.cloud.event.EventTypes;
-import com.cloud.event.UsageEventVO;
+import com.cloud.event.UsageEventUtils;
 import com.cloud.event.dao.EventDao;
 import com.cloud.event.dao.UsageEventDao;
 import com.cloud.exception.InvalidParameterValueException;
@@ -77,51 +50,19 @@
 import com.cloud.hypervisor.HypervisorGuruManager;
 import com.cloud.projects.Project;
 import com.cloud.projects.ProjectManager;
-import com.cloud.storage.LaunchPermissionVO;
-import com.cloud.storage.SnapshotVO;
-import com.cloud.storage.Storage;
+import com.cloud.storage.*;
 import com.cloud.storage.Storage.ImageFormat;
 import com.cloud.storage.Storage.TemplateType;
-import com.cloud.storage.StorageManager;
-import com.cloud.storage.StoragePool;
-import com.cloud.storage.StoragePoolHostVO;
-import com.cloud.storage.StoragePoolStatus;
-import com.cloud.storage.StoragePoolVO;
-import com.cloud.storage.Upload;
 import com.cloud.storage.Upload.Type;
-import com.cloud.storage.UploadVO;
-import com.cloud.storage.VMTemplateHostVO;
-import com.cloud.storage.VMTemplateStoragePoolVO;
-import com.cloud.storage.VMTemplateStorageResourceAssoc;
 import com.cloud.storage.VMTemplateStorageResourceAssoc.Status;
-import com.cloud.storage.VMTemplateSwiftVO;
-import com.cloud.storage.VMTemplateVO;
-import com.cloud.storage.VMTemplateZoneVO;
-import com.cloud.storage.VolumeVO;
-import com.cloud.storage.dao.LaunchPermissionDao;
-import com.cloud.storage.dao.SnapshotDao;
-import com.cloud.storage.dao.StoragePoolDao;
-import com.cloud.storage.dao.StoragePoolHostDao;
-import com.cloud.storage.dao.UploadDao;
-import com.cloud.storage.dao.VMTemplateDao;
-import com.cloud.storage.dao.VMTemplateHostDao;
-import com.cloud.storage.dao.VMTemplatePoolDao;
-import com.cloud.storage.dao.VMTemplateS3Dao;
-import com.cloud.storage.dao.VMTemplateSwiftDao;
-import com.cloud.storage.dao.VMTemplateZoneDao;
-import com.cloud.storage.dao.VolumeDao;
+import com.cloud.storage.dao.*;
 import com.cloud.storage.download.DownloadMonitor;
 import com.cloud.storage.s3.S3Manager;
 import com.cloud.storage.secondary.SecondaryStorageVmManager;
 import com.cloud.storage.swift.SwiftManager;
 import com.cloud.storage.upload.UploadMonitor;
 import com.cloud.template.TemplateAdapter.TemplateAdapterType;
-import com.cloud.user.Account;
-import com.cloud.user.AccountManager;
-import com.cloud.user.AccountService;
-import com.cloud.user.AccountVO;
-import com.cloud.user.ResourceLimitService;
-import com.cloud.user.UserContext;
+import com.cloud.user.*;
 import com.cloud.user.dao.AccountDao;
 import com.cloud.user.dao.UserAccountDao;
 import com.cloud.user.dao.UserDao;
@@ -132,12 +73,7 @@
 import com.cloud.utils.component.Inject;
 import com.cloud.utils.component.Manager;
 import com.cloud.utils.concurrency.NamedThreadFactory;
-import com.cloud.utils.db.DB;
-import com.cloud.utils.db.GlobalLock;
-import com.cloud.utils.db.JoinBuilder;
-import com.cloud.utils.db.SearchBuilder;
-import com.cloud.utils.db.SearchCriteria;
-import com.cloud.utils.db.Transaction;
+import com.cloud.utils.db.*;
 import com.cloud.utils.exception.CloudRuntimeException;
 import com.cloud.vm.UserVmManager;
 import com.cloud.vm.UserVmVO;
@@ -145,6 +81,21 @@
 import com.cloud.vm.VirtualMachine.State;
 import com.cloud.vm.dao.UserVmDao;
 import com.cloud.vm.dao.VMInstanceDao;
+import org.apache.cloudstack.acl.SecurityChecker.AccessType;
+import org.apache.cloudstack.api.BaseListTemplateOrIsoPermissionsCmd;
+import org.apache.cloudstack.api.BaseUpdateTemplateOrIsoPermissionsCmd;
+import org.apache.cloudstack.api.command.user.iso.*;
+import org.apache.cloudstack.api.command.user.template.*;
+import org.apache.log4j.Logger;
+
+import javax.ejb.Local;
+import javax.naming.ConfigurationException;
+import java.net.*;
+import java.util.*;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.ScheduledExecutorService;
+import java.util.concurrent.TimeUnit;
 
 
 @Local(value={TemplateManager.class, TemplateService.class})
@@ -823,8 +774,8 @@
                 _tmpltDao.addTemplateToZone(template, dstZoneId);
             	
             	if(account.getId() != Account.ACCOUNT_ID_SYSTEM){
-            	    UsageEventVO usageEvent = new UsageEventVO(copyEventType, account.getId(), dstZoneId, tmpltId, null, null, null, srcTmpltHost.getSize());
-            	    _usageEventDao.persist(usageEvent);
+                    UsageEventUtils.publishUsageEvent(copyEventType, account.getId(), dstZoneId, tmpltId, null, null, null, srcTmpltHost.getSize(),
+                            template.getClass().getName(), template.getUuid());
             	}
             	return true;
             }
diff --git a/server/src/com/cloud/user/AccountManagerImpl.java b/server/src/com/cloud/user/AccountManagerImpl.java
index b910a03..f60d305 100755
--- a/server/src/com/cloud/user/AccountManagerImpl.java
+++ b/server/src/com/cloud/user/AccountManagerImpl.java
@@ -36,6 +36,7 @@
 import javax.ejb.Local;
 import javax.naming.ConfigurationException;
 
+import com.cloud.event.ActionEventUtils;
 import org.apache.cloudstack.acl.ControlledEntity;
 import org.apache.cloudstack.acl.RoleType;
 import org.apache.cloudstack.acl.SecurityChecker;
@@ -64,7 +65,6 @@
 import com.cloud.domain.dao.DomainDao;
 import com.cloud.event.ActionEvent;
 import com.cloud.event.EventTypes;
-import com.cloud.event.EventUtils;
 import com.cloud.exception.AgentUnavailableException;
 import com.cloud.exception.CloudAuthenticationException;
 import com.cloud.exception.ConcurrentOperationException;
@@ -1744,7 +1744,7 @@
     public void logoutUser(Long userId) {
         UserAccount userAcct = _userAccountDao.findById(userId);
         if (userAcct != null) {
-            EventUtils.saveEvent(userId, userAcct.getAccountId(), userAcct.getDomainId(), EventTypes.EVENT_USER_LOGOUT, "user has logged out");
+            ActionEventUtils.onActionEvent(userId, userAcct.getAccountId(), userAcct.getDomainId(), EventTypes.EVENT_USER_LOGOUT, "user has logged out");
         } // else log some kind of error event? This likely means the user doesn't exist, or has been deleted...
     }
 
@@ -1875,10 +1875,10 @@
                 s_logger.debug("User: " + username + " in domain " + domainId + " has successfully logged in");
             }
             if (NetUtils.isValidIp(loginIpAddress)) {
-                EventUtils.saveEvent(user.getId(), user.getAccountId(), user.getDomainId(), EventTypes.EVENT_USER_LOGIN,
+                ActionEventUtils.onActionEvent(user.getId(), user.getAccountId(), user.getDomainId(), EventTypes.EVENT_USER_LOGIN,
                         "user has logged in from IP Address " + loginIpAddress);
             } else {
-                EventUtils.saveEvent(user.getId(), user.getAccountId(), user.getDomainId(), EventTypes.EVENT_USER_LOGIN,
+                ActionEventUtils.onActionEvent(user.getId(), user.getAccountId(), user.getDomainId(), EventTypes.EVENT_USER_LOGIN,
                         "user has logged in. The IP Address cannot be determined");
             }
             return user;
diff --git a/server/src/com/cloud/vm/UserVmManagerImpl.java b/server/src/com/cloud/vm/UserVmManagerImpl.java
index 3737450..969539c 100644
--- a/server/src/com/cloud/vm/UserVmManagerImpl.java
+++ b/server/src/com/cloud/vm/UserVmManagerImpl.java
@@ -54,7 +54,7 @@
 import com.cloud.domain.dao.DomainDao;
 import com.cloud.event.ActionEvent;
 import com.cloud.event.EventTypes;
-import com.cloud.event.UsageEventVO;
+import com.cloud.event.UsageEventUtils;
 import com.cloud.event.dao.UsageEventDao;
 import com.cloud.exception.*;
 import com.cloud.ha.HighAvailabilityManager;
@@ -245,8 +245,6 @@
     @Inject
     protected LoadBalancingRulesManager _lbMgr;
     @Inject
-    protected UsageEventDao _usageEventDao;
-    @Inject
     protected SSHKeyPairDao _sshKeyPairDao;
     @Inject
     protected UserVmDetailsDao _vmDetailsDao;
@@ -280,6 +278,8 @@
     PhysicalNetworkDao _physicalNetworkDao;
     @Inject
     VpcManager _vpcMgr;
+    @Inject
+    UsageEventDao _usageEventDao;
 
     protected ScheduledExecutorService _executor = null;
     protected int _expungeInterval;
@@ -841,7 +841,7 @@
     }
 
     @Override
-    @ActionEvent(eventType = EventTypes.EVENT_VOLUME_DETACH, eventDescription = "detaching volume", async = true)
+    @ActionEvent(eventType = EventTypes.EVENT_VOLUME_DETACH, eventDescription = "detaching volume",  async = true)
     public Volume detachVolumeFromVM(DetachVolumeCmd cmmd) {
         Account caller = UserContext.current().getCaller();
         if ((cmmd.getId() == null && cmmd.getDeviceId() == null && cmmd.getVirtualMachineId() == null) || (cmmd.getId() != null && (cmmd.getDeviceId() != null || cmmd.getVirtualMachineId() != null))
@@ -1372,9 +1372,9 @@
                         offeringId = offering.getId();
                     }
                 }
-                UsageEventVO usageEvent = new UsageEventVO(EventTypes.EVENT_VOLUME_CREATE, volume.getAccountId(), volume.getDataCenterId(), volume.getId(), volume.getName(), offeringId, templateId,
-                        volume.getSize());
-                _usageEventDao.persist(usageEvent);
+                UsageEventUtils.publishUsageEvent(EventTypes.EVENT_VOLUME_CREATE, volume.getAccountId(),
+                        volume.getDataCenterId(), volume.getId(), volume.getName(), offeringId, templateId,
+                        volume.getSize(), Volume.class.getName(), volume.getUuid());
             }
         }
 
@@ -1640,8 +1640,8 @@
             //check permissions
             _accountMgr.checkAccess(caller, null, true, snapshot);
 
-            if (snapshot.getStatus() != Snapshot.Status.BackedUp) {
-                throw new InvalidParameterValueException("Snapshot id=" + snapshotId + " is not in " + Snapshot.Status.BackedUp + " state yet and can't be used for template creation");
+            if (snapshot.getState() != Snapshot.State.BackedUp) {
+                throw new InvalidParameterValueException("Snapshot id=" + snapshotId + " is not in " + Snapshot.State.BackedUp + " state yet and can't be used for template creation");
             }
 
             /*
@@ -1888,9 +1888,10 @@
                 templateHostVO.setPhysicalSize(answer.getphysicalSize());
                 _templateHostDao.persist(templateHostVO);
 
-                UsageEventVO usageEvent = new UsageEventVO(EventTypes.EVENT_TEMPLATE_CREATE, privateTemplate.getAccountId(), secondaryStorageHost.getDataCenterId(), privateTemplate.getId(),
-                        privateTemplate.getName(), null, privateTemplate.getSourceTemplateId(), templateHostVO.getSize());
-                _usageEventDao.persist(usageEvent);
+                UsageEventUtils.publishUsageEvent(EventTypes.EVENT_TEMPLATE_CREATE, privateTemplate.getAccountId(),
+                        secondaryStorageHost.getDataCenterId(), privateTemplate.getId(),
+                        privateTemplate.getName(), null, privateTemplate.getSourceTemplateId(),
+                        templateHostVO.getSize(), VirtualMachineTemplate.class.getName(), privateTemplate.getUuid());
                 txn.commit();
             }
         } finally {
@@ -2835,8 +2836,9 @@
         }
         UserContext.current().setEventDetails("Vm Id: " + vm.getId());
 
-        UsageEventVO usageEvent = new UsageEventVO(EventTypes.EVENT_VM_CREATE, accountId, zone.getId(), vm.getId(), vm.getHostName(), offering.getId(), template.getId(), hypervisorType.toString());
-        _usageEventDao.persist(usageEvent);
+        UsageEventUtils.publishUsageEvent(EventTypes.EVENT_VM_CREATE, accountId, zone.getId(), vm.getId(),
+                vm.getHostName(), offering.getId(), template.getId(), hypervisorType.toString(),
+                VirtualMachine.class.getName(), vm.getUuid());
 
         _resourceLimitMgr.incrementResourceCount(accountId, ResourceType.user_vm);
         txn.commit();
@@ -3006,8 +3008,9 @@
         for (NicVO nic : nics) {
             NetworkVO network = _networkDao.findById(nic.getNetworkId());
             long isDefault = (nic.isDefaultNic()) ? 1 : 0;
-            UsageEventVO usageEvent = new UsageEventVO(EventTypes.EVENT_NETWORK_OFFERING_ASSIGN, vm.getAccountId(), vm.getDataCenterIdToDeployIn(), vm.getId(), vm.getHostName(), network.getNetworkOfferingId(), null, isDefault);
-            _usageEventDao.persist(usageEvent);
+            UsageEventUtils.publishUsageEvent(EventTypes.EVENT_NETWORK_OFFERING_ASSIGN, vm.getAccountId(),
+                    vm.getDataCenterIdToDeployIn(), vm.getId(), vm.getHostName(), network.getNetworkOfferingId(),
+                    null, isDefault, VirtualMachine.class.getName(), vm.getUuid());
             if (network.getTrafficType() == TrafficType.Guest) {
                 originalIp = nic.getIp4Address();
                 guestNic = nic;
@@ -3270,8 +3273,9 @@
             List<VolumeVO> volumes = _volsDao.findByInstance(vmId);
             for (VolumeVO volume : volumes) {
                 if (volume.getVolumeType().equals(Volume.Type.ROOT)) {
-                    UsageEventVO usageEvent = new UsageEventVO(EventTypes.EVENT_VOLUME_DELETE, volume.getAccountId(), volume.getDataCenterId(), volume.getId(), volume.getName());
-                    _usageEventDao.persist(usageEvent);
+                    UsageEventUtils.publishUsageEvent(EventTypes.EVENT_VOLUME_DELETE, volume.getAccountId(),
+                            volume.getDataCenterId(), volume.getId(), volume.getName(), Volume.class.getName(),
+                            volume.getUuid());
                 }
             }
 
@@ -3721,8 +3725,9 @@
         Transaction txn = Transaction.currentTxn();
         txn.start();
         //generate destroy vm event for usage
-        _usageEventDao.persist(new UsageEventVO(EventTypes.EVENT_VM_DESTROY, vm.getAccountId(), vm.getDataCenterIdToDeployIn(), vm.getId(),
-                vm.getHostName(), vm.getServiceOfferingId(), vm.getTemplateId(), vm.getHypervisorType().toString()));
+        UsageEventUtils.publishUsageEvent(EventTypes.EVENT_VM_DESTROY, vm.getAccountId(), vm.getDataCenterIdToDeployIn(), vm.getId(),
+                vm.getHostName(), vm.getServiceOfferingId(), vm.getTemplateId(), vm.getHypervisorType().toString(),
+                VirtualMachine.class.getName(), vm.getUuid());
         // update resource counts
         _resourceLimitMgr.decrementResourceCount(oldAccount.getAccountId(), ResourceType.user_vm);
 
@@ -3734,13 +3739,16 @@
         // OS 2: update volume
         List<VolumeVO> volumes = _volsDao.findByInstance(cmd.getVmId());
         for (VolumeVO volume : volumes) {
-            _usageEventDao.persist(new UsageEventVO(EventTypes.EVENT_VOLUME_DELETE, volume.getAccountId(), volume.getDataCenterId(), volume.getId(), volume.getName()));
+            UsageEventUtils.publishUsageEvent(EventTypes.EVENT_VOLUME_DELETE, volume.getAccountId(),
+                    volume.getDataCenterId(), volume.getId(), volume.getName(), Volume.class.getName(), volume.getUuid());
             _resourceLimitMgr.decrementResourceCount(oldAccount.getAccountId(), ResourceType.volume);
             volume.setAccountId(newAccount.getAccountId());
             _volsDao.persist(volume);
             _resourceLimitMgr.incrementResourceCount(newAccount.getAccountId(), ResourceType.volume);
-            _usageEventDao.persist(new UsageEventVO(EventTypes.EVENT_VOLUME_CREATE, volume.getAccountId(), volume.getDataCenterId(), volume.getId(), volume.getName(),
-                    volume.getDiskOfferingId(), volume.getTemplateId(), volume.getSize()));
+            UsageEventUtils.publishUsageEvent(EventTypes.EVENT_VOLUME_CREATE, volume.getAccountId(),
+                    volume.getDataCenterId(), volume.getId(), volume.getName(),
+                    volume.getDiskOfferingId(), volume.getTemplateId(), volume.getSize(), Volume.class.getName(),
+                    volume.getUuid());
             //snapshots: mark these removed in db
             List<SnapshotVO> snapshots = _snapshotDao.listByVolumeIdIncludingRemoved(volume.getId());
             for (SnapshotVO snapshot: snapshots){
@@ -3750,8 +3758,9 @@
 
         _resourceLimitMgr.incrementResourceCount(newAccount.getAccountId(), ResourceType.user_vm);
         //generate usage events to account for this change
-        _usageEventDao.persist(new UsageEventVO(EventTypes.EVENT_VM_CREATE, vm.getAccountId(), vm.getDataCenterIdToDeployIn(), vm.getId(),
-                vm.getHostName(), vm.getServiceOfferingId(),  vm.getTemplateId(), vm.getHypervisorType().toString()));
+        UsageEventUtils.publishUsageEvent(EventTypes.EVENT_VM_CREATE, vm.getAccountId(), vm.getDataCenterIdToDeployIn(), vm.getId(),
+                vm.getHostName(), vm.getServiceOfferingId(), vm.getTemplateId(), vm.getHypervisorType().toString(),
+                VirtualMachine.class.getName(), vm.getUuid());
 
         txn.commit();
 
diff --git a/server/src/com/cloud/vm/UserVmStateListener.java b/server/src/com/cloud/vm/UserVmStateListener.java
index 4d9bcc5..786387f 100644
--- a/server/src/com/cloud/vm/UserVmStateListener.java
+++ b/server/src/com/cloud/vm/UserVmStateListener.java
@@ -16,24 +16,48 @@
 // under the License.
 package com.cloud.vm;
 
-import java.util.List;
-
+import com.cloud.event.EventCategory;
 import com.cloud.event.EventTypes;
-import com.cloud.event.UsageEventVO;
+import com.cloud.event.UsageEventUtils;
 import com.cloud.event.dao.UsageEventDao;
+import com.cloud.network.Network;
 import com.cloud.network.NetworkVO;
 import com.cloud.network.dao.NetworkDao;
+import com.cloud.server.ManagementServer;
+import com.cloud.utils.component.Adapters;
+import com.cloud.utils.component.ComponentLocator;
 import com.cloud.utils.fsm.StateListener;
 import com.cloud.vm.VirtualMachine.Event;
 import com.cloud.vm.VirtualMachine.State;
 import com.cloud.vm.dao.NicDao;
+import org.apache.cloudstack.framework.events.EventBus;
+import org.apache.cloudstack.framework.events.EventBusException;
+import org.apache.log4j.Logger;
+
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
 
 public class UserVmStateListener implements StateListener<State, VirtualMachine.Event, VirtualMachine> {
 
     protected UsageEventDao _usageEventDao;
     protected NetworkDao _networkDao;
     protected NicDao _nicDao;
-    
+    private static final Logger s_logger = Logger.getLogger(UserVmStateListener.class);
+
+    // get the event bus provider if configured
+    protected static EventBus _eventBus = null;
+    static {
+        Adapters<EventBus> eventBusImpls = ComponentLocator.getLocator(ManagementServer.Name).getAdapters(EventBus.class);
+        if (eventBusImpls != null) {
+            Enumeration<EventBus> eventBusenum = eventBusImpls.enumeration();
+            if (eventBusenum != null && eventBusenum.hasMoreElements()) {
+                _eventBus = eventBusenum.nextElement(); // configure event bus if configured
+            }
+        }
+    }
+
     public UserVmStateListener(UsageEventDao usageEventDao, NetworkDao networkDao, NicDao nicDao) {
         this._usageEventDao = usageEventDao;
         this._networkDao = networkDao;
@@ -42,6 +66,7 @@
     
     @Override
     public boolean preStateTransitionEvent(State oldState, Event event, State newState, VirtualMachine vo, boolean status, Object opaque) {
+        pubishOnEventBus(event.name(), "preStateTransitionEvent", vo, oldState, newState);
         return true;
     }
 
@@ -54,29 +79,62 @@
         if(vo.getType() != VirtualMachine.Type.User){
             return true;
         }
-        
+
+        pubishOnEventBus(event.name(), "postStateTransitionEvent", vo, oldState, newState);
+
         if (VirtualMachine.State.isVmCreated(oldState, event, newState)) {
-            UsageEventVO usageEvent = new UsageEventVO(EventTypes.EVENT_VM_CREATE, vo.getAccountId(), vo.getDataCenterIdToDeployIn(), vo.getId(), vo.getHostName(), vo.getServiceOfferingId(), 
+            UsageEventUtils.saveUsageEvent(EventTypes.EVENT_VM_CREATE, vo.getAccountId(), vo.getDataCenterIdToDeployIn(), vo.getId(), vo.getHostName(), vo.getServiceOfferingId(),
                     vo.getTemplateId(), vo.getHypervisorType().toString());
-            _usageEventDao.persist(usageEvent);
         } else if (VirtualMachine.State.isVmStarted(oldState, event, newState)) {
-            UsageEventVO usageEvent = new UsageEventVO(EventTypes.EVENT_VM_START, vo.getAccountId(), vo.getDataCenterIdToDeployIn(), vo.getId(), vo.getHostName(), vo.getServiceOfferingId(), 
+            UsageEventUtils.saveUsageEvent(EventTypes.EVENT_VM_START, vo.getAccountId(), vo.getDataCenterIdToDeployIn(), vo.getId(), vo.getHostName(), vo.getServiceOfferingId(),
                     vo.getTemplateId(), vo.getHypervisorType().toString());
-            _usageEventDao.persist(usageEvent);
         } else if (VirtualMachine.State.isVmStopped(oldState, event, newState)) {
-            UsageEventVO usageEvent = new UsageEventVO(EventTypes.EVENT_VM_STOP, vo.getAccountId(), vo.getDataCenterIdToDeployIn(), vo.getId(), vo.getHostName());
-            _usageEventDao.persist(usageEvent);
+            UsageEventUtils.saveUsageEvent(EventTypes.EVENT_VM_STOP, vo.getAccountId(), vo.getDataCenterIdToDeployIn(), vo.getId(), vo.getHostName());
             List<NicVO> nics = _nicDao.listByVmId(vo.getId());
             for (NicVO nic : nics) {
                 NetworkVO network = _networkDao.findById(nic.getNetworkId());
-                usageEvent = new UsageEventVO(EventTypes.EVENT_NETWORK_OFFERING_REMOVE, vo.getAccountId(), vo.getDataCenterIdToDeployIn(), vo.getId(), null, network.getNetworkOfferingId(), null, 0L);
-                _usageEventDao.persist(usageEvent);
+                UsageEventUtils.saveUsageEvent(EventTypes.EVENT_NETWORK_OFFERING_REMOVE, vo.getAccountId(), vo.getDataCenterIdToDeployIn(), vo.getId(), null, network.getNetworkOfferingId(), null, 0L);
             }
         } else if (VirtualMachine.State.isVmDestroyed(oldState, event, newState)) {
-            UsageEventVO usageEvent = new UsageEventVO(EventTypes.EVENT_VM_DESTROY, vo.getAccountId(), vo.getDataCenterIdToDeployIn(), vo.getId(), vo.getHostName(), vo.getServiceOfferingId(), 
+            UsageEventUtils.saveUsageEvent(EventTypes.EVENT_VM_DESTROY, vo.getAccountId(), vo.getDataCenterIdToDeployIn(), vo.getId(), vo.getHostName(), vo.getServiceOfferingId(),
                     vo.getTemplateId(), vo.getHypervisorType().toString());
-            _usageEventDao.persist(usageEvent);
         } 
         return true;
     }
+
+    private void pubishOnEventBus(String event, String status, VirtualMachine vo, VirtualMachine.State oldState, VirtualMachine.State newState) {
+
+        if (_eventBus == null) {
+            return; // no provider is configured to provide events bus, so just return
+        }
+
+        String resourceName = getEntityFromClassName(Network.class.getName());
+        org.apache.cloudstack.framework.events.Event eventMsg =  new org.apache.cloudstack.framework.events.Event(
+                ManagementServer.Name,
+                EventCategory.RESOURCE_STATE_CHANGE_EVENT.getName(),
+                event,
+                resourceName,
+                vo.getUuid());
+        Map<String, String> eventDescription = new HashMap<String, String>();
+        eventDescription.put("resource", resourceName);
+        eventDescription.put("id", vo.getUuid());
+        eventDescription.put("old-state", oldState.name());
+        eventDescription.put("new-state", newState.name());
+        eventMsg.setDescription(eventDescription);
+        try {
+            _eventBus.publish(eventMsg);
+        } catch (EventBusException e) {
+            s_logger.warn("Failed to publish state change event on the the event bus.");
+        }
+
+    }
+
+    private String getEntityFromClassName(String entityClassName) {
+        int index = entityClassName.lastIndexOf(".");
+        String entityName = entityClassName;
+        if (index != -1) {
+            entityName = entityClassName.substring(index+1);
+        }
+        return entityName;
+    }
 }
diff --git a/server/test/com/cloud/snapshot/SnapshotDaoTest.java b/server/test/com/cloud/snapshot/SnapshotDaoTest.java
index c412f49..5dc9b91 100644
--- a/server/test/com/cloud/snapshot/SnapshotDaoTest.java
+++ b/server/test/com/cloud/snapshot/SnapshotDaoTest.java
@@ -16,24 +16,23 @@
 // under the License.
 package com.cloud.snapshot;
 
-import java.util.List;
-
 import com.cloud.storage.Snapshot;
 import com.cloud.storage.SnapshotVO;
 import com.cloud.storage.dao.SnapshotDaoImpl;
 import com.cloud.utils.component.ComponentLocator;
-
 import junit.framework.Assert;
 import junit.framework.TestCase;
 
+import java.util.List;
+
 public class SnapshotDaoTest extends TestCase {
 	
     public void testListBy() {
         SnapshotDaoImpl dao = ComponentLocator.inject(SnapshotDaoImpl.class);
         
-        List<SnapshotVO> snapshots = dao.listByInstanceId(3, Snapshot.Status.BackedUp);
+        List<SnapshotVO> snapshots = dao.listByInstanceId(3, Snapshot.State.BackedUp);
         for(SnapshotVO snapshot : snapshots) {
-            Assert.assertTrue(snapshot.getStatus() == Snapshot.Status.BackedUp);
+            Assert.assertTrue(snapshot.getState() == Snapshot.State.BackedUp);
         }
     }
 }
diff --git a/server/test/com/cloud/vpc/dao/MockNetworkDaoImpl.java b/server/test/com/cloud/vpc/dao/MockNetworkDaoImpl.java
index 7c9a582..f0e4b54 100644
--- a/server/test/com/cloud/vpc/dao/MockNetworkDaoImpl.java
+++ b/server/test/com/cloud/vpc/dao/MockNetworkDaoImpl.java
@@ -16,12 +16,7 @@
 // under the License.
 package com.cloud.vpc.dao;
 
-import java.util.ArrayList;
-import java.util.List;
-import java.util.Map;
-
-import javax.ejb.Local;
-
+import com.cloud.network.Network;
 import com.cloud.network.Network.GuestType;
 import com.cloud.network.NetworkAccountVO;
 import com.cloud.network.NetworkVO;
@@ -31,6 +26,11 @@
 import com.cloud.utils.db.GenericDaoBase;
 import com.cloud.utils.db.SearchBuilder;
 
+import javax.ejb.Local;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+
 @Local(value = NetworkDao.class)
 @DB(txn = false)
 public class MockNetworkDaoImpl extends GenericDaoBase<NetworkVO, Long> implements NetworkDao{
@@ -342,6 +342,11 @@
         return 0;
     }
 
+    @Override
+    public boolean updateState(Network.State currentState, Network.Event event, Network.State nextState, Network vo, Object data) {
+        return true;
+    }
+
     /* (non-Javadoc)
      * @see com.cloud.network.dao.NetworkDao#listNetworksByAccount(long, long, com.cloud.network.Network.GuestType, boolean)
      */
diff --git a/tools/whisker/LICENSE b/tools/whisker/LICENSE
index 7efac5c..025cb33 100644
--- a/tools/whisker/LICENSE
+++ b/tools/whisker/LICENSE
@@ -748,7 +748,7 @@
             
             The Covered Software is a "commercial item," as that term is
             defined in 48 C.F.R. 2.101 (Oct. 1995), consisting of "commercial
-            computer software" (as that term is defined at 48 C.F.R. ¤
+            computer software" (as that term is defined at 48 C.F.R. �
             252.227-7014(a)(1)) and "commercial computer software
             documentation" as such terms are used in 48 C.F.R. 12.212 (Sept.
             1995). Consistent with 48 C.F.R. 12.212 and 48 C.F.R. 227.7202-1
@@ -1138,7 +1138,7 @@
             
             The Covered Software is a "commercial item," as that term is
             defined in 48 C.F.R. 2.101 (Oct. 1995), consisting of "commercial
-            computer software" (as that term is defined at 48 C.F.R. ¤
+            computer software" (as that term is defined at 48 C.F.R. �
             252.227-7014(a)(1)) and "commercial computer software
             documentation" as such terms are used in 48 C.F.R. 12.212 (Sept.
             1995). Consistent with 48 C.F.R. 12.212 and 48 C.F.R. 227.7202-1
@@ -1526,7 +1526,7 @@
             
             The Covered Software is a "commercial item," as that term is
             defined in 48 C.F.R. 2.101 (Oct. 1995), consisting of "commercial
-            computer software" (as that term is defined at 48 C.F.R. ¤
+            computer software" (as that term is defined at 48 C.F.R. �
             252.227-7014(a)(1)) and "commercial computer software
             documentation" as such terms are used in 48 C.F.R. 12.212 (Sept.
             1995). Consistent with 48 C.F.R. 12.212 and 48 C.F.R. 227.7202-1
@@ -1867,7 +1867,9 @@
             slf4j-api-1.5.11.jar  from https://github.com/qos-ch/slf4j
             slf4j-jdk14-1.5.11.jar  from https://github.com/qos-ch/slf4j
 
-    licensed under the Mozilla Public License, Version 1.0 http://www.mozilla.org/MPL/1.1/  (as follows)
+
+    licensed under the Mozilla Public License, Version 1.1 http://www.mozilla.org/MPL/1.1/  (as follows)
+
  
             
                                       MOZILLA PUBLIC LICENSE
@@ -2344,6 +2346,486 @@
         from Shigeru Chiba  http://www.csg.ci.i.u-tokyo.ac.jp/~chiba/javassist/ 
             javassist-3.9.0.GA.jar  from http://sourceforge.net/projects/jboss/files/Javassist/
 
+
+    licensed under the Mozilla Public License, Version 1.1 http://www.mozilla.org/MPL/1.1/  (as follows)
+
+            Copyright (c) 2007-2012 VMware, Inc.  All Rights Reserved.
+
+                                      MOZILLA PUBLIC LICENSE
+                                            Version 1.1
+
+                                          ---------------
+
+            1. Definitions.
+
+                 1.0.1. "Commercial Use" means distribution or otherwise making the
+                 Covered Code available to a third party.
+
+                 1.1. "Contributor" means each entity that creates or contributes to
+                 the creation of Modifications.
+
+                 1.2. "Contributor Version" means the combination of the Original
+                 Code, prior Modifications used by a Contributor, and the Modifications
+                 made by that particular Contributor.
+
+                 1.3. "Covered Code" means the Original Code or Modifications or the
+                 combination of the Original Code and Modifications, in each case
+                 including portions thereof.
+
+                 1.4. "Electronic Distribution Mechanism" means a mechanism generally
+                 accepted in the software development community for the electronic
+                 transfer of data.
+
+                 1.5. "Executable" means Covered Code in any form other than Source
+                 Code.
+
+                 1.6. "Initial Developer" means the individual or entity identified
+                 as the Initial Developer in the Source Code notice required by Exhibit
+                 A.
+
+                 1.7. "Larger Work" means a work which combines Covered Code or
+                 portions thereof with code not governed by the terms of this License.
+
+                 1.8. "License" means this document.
+
+                 1.8.1. "Licensable" means having the right to grant, to the maximum
+                 extent possible, whether at the time of the initial grant or
+                 subsequently acquired, any and all of the rights conveyed herein.
+
+                 1.9. "Modifications" means any addition to or deletion from the
+                 substance or structure of either the Original Code or any previous
+                 Modifications. When Covered Code is released as a series of files, a
+                 Modification is:
+                      A. Any addition to or deletion from the contents of a file
+                      containing Original Code or previous Modifications.
+
+                      B. Any new file that contains any part of the Original Code or
+                      previous Modifications.
+
+                 1.10. "Original Code" means Source Code of computer software code
+                 which is described in the Source Code notice required by Exhibit A as
+                 Original Code, and which, at the time of its release under this
+                 License is not already Covered Code governed by this License.
+
+                 1.10.1. "Patent Claims" means any patent claim(s), now owned or
+                 hereafter acquired, including without limitation,  method, process,
+                 and apparatus claims, in any patent Licensable by grantor.
+
+                 1.11. "Source Code" means the preferred form of the Covered Code for
+                 making modifications to it, including all modules it contains, plus
+                 any associated interface definition files, scripts used to control
+                 compilation and installation of an Executable, or source code
+                 differential comparisons against either the Original Code or another
+                 well known, available Covered Code of the Contributor's choice. The
+                 Source Code can be in a compressed or archival form, provided the
+                 appropriate decompression or de-archiving software is widely available
+                 for no charge.
+
+                 1.12. "You" (or "Your")  means an individual or a legal entity
+                 exercising rights under, and complying with all of the terms of, this
+                 License or a future version of this License issued under Section 6.1.
+                 For legal entities, "You" includes any entity which controls, is
+                 controlled by, or is under common control with You. For purposes of
+                 this definition, "control" means (a) the power, direct or indirect,
+                 to cause the direction or management of such entity, whether by
+                 contract or otherwise, or (b) ownership of more than fifty percent
+                 (50%) of the outstanding shares or beneficial ownership of such
+                 entity.
+
+            2. Source Code License.
+
+                 2.1. The Initial Developer Grant.
+                 The Initial Developer hereby grants You a world-wide, royalty-free,
+                 non-exclusive license, subject to third party intellectual property
+                 claims:
+                      (a)  under intellectual property rights (other than patent or
+                      trademark) Licensable by Initial Developer to use, reproduce,
+                      modify, display, perform, sublicense and distribute the Original
+                      Code (or portions thereof) with or without Modifications, and/or
+                      as part of a Larger Work; and
+
+                      (b) under Patents Claims infringed by the making, using or
+                      selling of Original Code, to make, have made, use, practice,
+                      sell, and offer for sale, and/or otherwise dispose of the
+                      Original Code (or portions thereof).
+
+                      (c) the licenses granted in this Section 2.1(a) and (b) are
+                      effective on the date Initial Developer first distributes
+                      Original Code under the terms of this License.
+
+                      (d) Notwithstanding Section 2.1(b) above, no patent license is
+                      granted: 1) for code that You delete from the Original Code; 2)
+                      separate from the Original Code;  or 3) for infringements caused
+                      by: i) the modification of the Original Code or ii) the
+                      combination of the Original Code with other software or devices.
+
+                 2.2. Contributor Grant.
+                 Subject to third party intellectual property claims, each Contributor
+                 hereby grants You a world-wide, royalty-free, non-exclusive license
+
+                      (a)  under intellectual property rights (other than patent or
+                      trademark) Licensable by Contributor, to use, reproduce, modify,
+                      display, perform, sublicense and distribute the Modifications
+                      created by such Contributor (or portions thereof) either on an
+                      unmodified basis, with other Modifications, as Covered Code
+                      and/or as part of a Larger Work; and
+
+                      (b) under Patent Claims infringed by the making, using, or
+                      selling of  Modifications made by that Contributor either alone
+                      and/or in combination with its Contributor Version (or portions
+                      of such combination), to make, use, sell, offer for sale, have
+                      made, and/or otherwise dispose of: 1) Modifications made by that
+                      Contributor (or portions thereof); and 2) the combination of
+                      Modifications made by that Contributor with its Contributor
+                      Version (or portions of such combination).
+
+                      (c) the licenses granted in Sections 2.2(a) and 2.2(b) are
+                      effective on the date Contributor first makes Commercial Use of
+                      the Covered Code.
+
+                      (d)    Notwithstanding Section 2.2(b) above, no patent license is
+                      granted: 1) for any code that Contributor has deleted from the
+                      Contributor Version; 2)  separate from the Contributor Version;
+                      3)  for infringements caused by: i) third party modifications of
+                      Contributor Version or ii)  the combination of Modifications made
+                      by that Contributor with other software  (except as part of the
+                      Contributor Version) or other devices; or 4) under Patent Claims
+                      infringed by Covered Code in the absence of Modifications made by
+                      that Contributor.
+
+            3. Distribution Obligations.
+
+                 3.1. Application of License.
+                 The Modifications which You create or to which You contribute are
+                 governed by the terms of this License, including without limitation
+                 Section 2.2. The Source Code version of Covered Code may be
+                 distributed only under the terms of this License or a future version
+                 of this License released under Section 6.1, and You must include a
+                 copy of this License with every copy of the Source Code You
+                 distribute. You may not offer or impose any terms on any Source Code
+                 version that alters or restricts the applicable version of this
+                 License or the recipients' rights hereunder. However, You may include
+                 an additional document offering the additional rights described in
+                 Section 3.5.
+
+                 3.2. Availability of Source Code.
+                 Any Modification which You create or to which You contribute must be
+                 made available in Source Code form under the terms of this License
+                 either on the same media as an Executable version or via an accepted
+                 Electronic Distribution Mechanism to anyone to whom you made an
+                 Executable version available; and if made available via Electronic
+                 Distribution Mechanism, must remain available for at least twelve (12)
+                 months after the date it initially became available, or at least six
+                 (6) months after a subsequent version of that particular Modification
+                 has been made available to such recipients. You are responsible for
+                 ensuring that the Source Code version remains available even if the
+                 Electronic Distribution Mechanism is maintained by a third party.
+
+                 3.3. Description of Modifications.
+                 You must cause all Covered Code to which You contribute to contain a
+                 file documenting the changes You made to create that Covered Code and
+                 the date of any change. You must include a prominent statement that
+                 the Modification is derived, directly or indirectly, from Original
+                 Code provided by the Initial Developer and including the name of the
+                 Initial Developer in (a) the Source Code, and (b) in any notice in an
+                 Executable version or related documentation in which You describe the
+                 origin or ownership of the Covered Code.
+
+                 3.4. Intellectual Property Matters
+                      (a) Third Party Claims.
+                      If Contributor has knowledge that a license under a third party's
+                      intellectual property rights is required to exercise the rights
+                      granted by such Contributor under Sections 2.1 or 2.2,
+                      Contributor must include a text file with the Source Code
+                      distribution titled "LEGAL" which describes the claim and the
+                      party making the claim in sufficient detail that a recipient will
+                      know whom to contact. If Contributor obtains such knowledge after
+                      the Modification is made available as described in Section 3.2,
+                      Contributor shall promptly modify the LEGAL file in all copies
+                      Contributor makes available thereafter and shall take other steps
+                      (such as notifying appropriate mailing lists or newsgroups)
+                      reasonably calculated to inform those who received the Covered
+                      Code that new knowledge has been obtained.
+
+                      (b) Contributor APIs.
+                      If Contributor's Modifications include an application programming
+                      interface and Contributor has knowledge of patent licenses which
+                      are reasonably necessary to implement that API, Contributor must
+                      also include this information in the LEGAL file.
+
+                           (c)    Representations.
+                      Contributor represents that, except as disclosed pursuant to
+                      Section 3.4(a) above, Contributor believes that Contributor's
+                      Modifications are Contributor's original creation(s) and/or
+                      Contributor has sufficient rights to grant the rights conveyed by
+                      this License.
+
+                 3.5. Required Notices.
+                 You must duplicate the notice in Exhibit A in each file of the Source
+                 Code.  If it is not possible to put such notice in a particular Source
+                 Code file due to its structure, then You must include such notice in a
+                 location (such as a relevant directory) where a user would be likely
+                 to look for such a notice.  If You created one or more Modification(s)
+                 You may add your name as a Contributor to the notice described in
+                 Exhibit A.  You must also duplicate this License in any documentation
+                 for the Source Code where You describe recipients' rights or ownership
+                 rights relating to Covered Code.  You may choose to offer, and to
+                 charge a fee for, warranty, support, indemnity or liability
+                 obligations to one or more recipients of Covered Code. However, You
+                 may do so only on Your own behalf, and not on behalf of the Initial
+                 Developer or any Contributor. You must make it absolutely clear than
+                 any such warranty, support, indemnity or liability obligation is
+                 offered by You alone, and You hereby agree to indemnify the Initial
+                 Developer and every Contributor for any liability incurred by the
+                 Initial Developer or such Contributor as a result of warranty,
+                 support, indemnity or liability terms You offer.
+
+                 3.6. Distribution of Executable Versions.
+                 You may distribute Covered Code in Executable form only if the
+                 requirements of Section 3.1-3.5 have been met for that Covered Code,
+                 and if You include a notice stating that the Source Code version of
+                 the Covered Code is available under the terms of this License,
+                 including a description of how and where You have fulfilled the
+                 obligations of Section 3.2. The notice must be conspicuously included
+                 in any notice in an Executable version, related documentation or
+                 collateral in which You describe recipients' rights relating to the
+                 Covered Code. You may distribute the Executable version of Covered
+                 Code or ownership rights under a license of Your choice, which may
+                 contain terms different from this License, provided that You are in
+                 compliance with the terms of this License and that the license for the
+                 Executable version does not attempt to limit or alter the recipient's
+                 rights in the Source Code version from the rights set forth in this
+                 License. If You distribute the Executable version under a different
+                 license You must make it absolutely clear that any terms which differ
+                 from this License are offered by You alone, not by the Initial
+                 Developer or any Contributor. You hereby agree to indemnify the
+                 Initial Developer and every Contributor for any liability incurred by
+                 the Initial Developer or such Contributor as a result of any such
+                 terms You offer.
+
+                 3.7. Larger Works.
+                 You may create a Larger Work by combining Covered Code with other code
+                 not governed by the terms of this License and distribute the Larger
+                 Work as a single product. In such a case, You must make sure the
+                 requirements of this License are fulfilled for the Covered Code.
+
+            4. Inability to Comply Due to Statute or Regulation.
+
+                 If it is impossible for You to comply with any of the terms of this
+                 License with respect to some or all of the Covered Code due to
+                 statute, judicial order, or regulation then You must: (a) comply with
+                 the terms of this License to the maximum extent possible; and (b)
+                 describe the limitations and the code they affect. Such description
+                 must be included in the LEGAL file described in Section 3.4 and must
+                 be included with all distributions of the Source Code. Except to the
+                 extent prohibited by statute or regulation, such description must be
+                 sufficiently detailed for a recipient of ordinary skill to be able to
+                 understand it.
+
+            5. Application of this License.
+
+                 This License applies to code to which the Initial Developer has
+                 attached the notice in Exhibit A and to related Covered Code.
+
+            6. Versions of the License.
+
+                 6.1. New Versions.
+                 Netscape Communications Corporation ("Netscape") may publish revised
+                 and/or new versions of the License from time to time. Each version
+                 will be given a distinguishing version number.
+
+                 6.2. Effect of New Versions.
+                 Once Covered Code has been published under a particular version of the
+                 License, You may always continue to use it under the terms of that
+                 version. You may also choose to use such Covered Code under the terms
+                 of any subsequent version of the License published by Netscape. No one
+                 other than Netscape has the right to modify the terms applicable to
+                 Covered Code created under this License.
+
+                 6.3. Derivative Works.
+                 If You create or use a modified version of this License (which you may
+                 only do in order to apply it to code which is not already Covered Code
+                 governed by this License), You must (a) rename Your license so that
+                 the phrases "Mozilla", "MOZILLAPL", "MOZPL", "Netscape",
+                 "MPL", "NPL" or any confusingly similar phrase do not appear in your
+                 license (except to note that your license differs from this License)
+                 and (b) otherwise make it clear that Your version of the license
+                 contains terms which differ from the Mozilla Public License and
+                 Netscape Public License. (Filling in the name of the Initial
+                 Developer, Original Code or Contributor in the notice described in
+                 Exhibit A shall not of themselves be deemed to be modifications of
+                 this License.)
+
+            7. DISCLAIMER OF WARRANTY.
+
+                 COVERED CODE IS PROVIDED UNDER THIS LICENSE ON AN "AS IS" BASIS,
+                 WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING,
+                 WITHOUT LIMITATION, WARRANTIES THAT THE COVERED CODE IS FREE OF
+                 DEFECTS, MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE OR NON-INFRINGING.
+                 THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE COVERED CODE
+                 IS WITH YOU. SHOULD ANY COVERED CODE PROVE DEFECTIVE IN ANY RESPECT,
+                 YOU (NOT THE INITIAL DEVELOPER OR ANY OTHER CONTRIBUTOR) ASSUME THE
+                 COST OF ANY NECESSARY SERVICING, REPAIR OR CORRECTION. THIS DISCLAIMER
+                 OF WARRANTY CONSTITUTES AN ESSENTIAL PART OF THIS LICENSE. NO USE OF
+                 ANY COVERED CODE IS AUTHORIZED HEREUNDER EXCEPT UNDER THIS DISCLAIMER.
+
+            8. TERMINATION.
+
+                 8.1.  This License and the rights granted hereunder will terminate
+                 automatically if You fail to comply with terms herein and fail to cure
+                 such breach within 30 days of becoming aware of the breach. All
+                 sublicenses to the Covered Code which are properly granted shall
+                 survive any termination of this License. Provisions which, by their
+                 nature, must remain in effect beyond the termination of this License
+                 shall survive.
+
+                 8.2.  If You initiate litigation by asserting a patent infringement
+                 claim (excluding declatory judgment actions) against Initial Developer
+                 or a Contributor (the Initial Developer or Contributor against whom
+                 You file such action is referred to as "Participant")  alleging that:
+
+                 (a)  such Participant's Contributor Version directly or indirectly
+                 infringes any patent, then any and all rights granted by such
+                 Participant to You under Sections 2.1 and/or 2.2 of this License
+                 shall, upon 60 days notice from Participant terminate prospectively,
+                 unless if within 60 days after receipt of notice You either: (i)
+                 agree in writing to pay Participant a mutually agreeable reasonable
+                 royalty for Your past and future use of Modifications made by such
+                 Participant, or (ii) withdraw Your litigation claim with respect to
+                 the Contributor Version against such Participant.  If within 60 days
+                 of notice, a reasonable royalty and payment arrangement are not
+                 mutually agreed upon in writing by the parties or the litigation claim
+                 is not withdrawn, the rights granted by Participant to You under
+                 Sections 2.1 and/or 2.2 automatically terminate at the expiration of
+                 the 60 day notice period specified above.
+
+                 (b)  any software, hardware, or device, other than such Participant's
+                 Contributor Version, directly or indirectly infringes any patent, then
+                 any rights granted to You by such Participant under Sections 2.1(b)
+                 and 2.2(b) are revoked effective as of the date You first made, used,
+                 sold, distributed, or had made, Modifications made by that
+                 Participant.
+
+                 8.3.  If You assert a patent infringement claim against Participant
+                 alleging that such Participant's Contributor Version directly or
+                 indirectly infringes any patent where such claim is resolved (such as
+                 by license or settlement) prior to the initiation of patent
+                 infringement litigation, then the reasonable value of the licenses
+                 granted by such Participant under Sections 2.1 or 2.2 shall be taken
+                 into account in determining the amount or value of any payment or
+                 license.
+
+                 8.4.  In the event of termination under Sections 8.1 or 8.2 above,
+                 all end user license agreements (excluding distributors and resellers)
+                 which have been validly granted by You or any distributor hereunder
+                 prior to termination shall survive termination.
+
+            9. LIMITATION OF LIABILITY.
+
+                 UNDER NO CIRCUMSTANCES AND UNDER NO LEGAL THEORY, WHETHER TORT
+                 (INCLUDING NEGLIGENCE), CONTRACT, OR OTHERWISE, SHALL YOU, THE INITIAL
+                 DEVELOPER, ANY OTHER CONTRIBUTOR, OR ANY DISTRIBUTOR OF COVERED CODE,
+                 OR ANY SUPPLIER OF ANY OF SUCH PARTIES, BE LIABLE TO ANY PERSON FOR
+                 ANY INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES OF ANY
+                 CHARACTER INCLUDING, WITHOUT LIMITATION, DAMAGES FOR LOSS OF GOODWILL,
+                 WORK STOPPAGE, COMPUTER FAILURE OR MALFUNCTION, OR ANY AND ALL OTHER
+                 COMMERCIAL DAMAGES OR LOSSES, EVEN IF SUCH PARTY SHALL HAVE BEEN
+                 INFORMED OF THE POSSIBILITY OF SUCH DAMAGES. THIS LIMITATION OF
+                 LIABILITY SHALL NOT APPLY TO LIABILITY FOR DEATH OR PERSONAL INJURY
+                 RESULTING FROM SUCH PARTY'S NEGLIGENCE TO THE EXTENT APPLICABLE LAW
+                 PROHIBITS SUCH LIMITATION. SOME JURISDICTIONS DO NOT ALLOW THE
+                 EXCLUSION OR LIMITATION OF INCIDENTAL OR CONSEQUENTIAL DAMAGES, SO
+                 THIS EXCLUSION AND LIMITATION MAY NOT APPLY TO YOU.
+
+            10. U.S. GOVERNMENT END USERS.
+
+                 The Covered Code is a "commercial item," as that term is defined in
+                 48 C.F.R. 2.101 (Oct. 1995), consisting of "commercial computer
+                 software" and "commercial computer software documentation," as such
+                 terms are used in 48 C.F.R. 12.212 (Sept. 1995). Consistent with 48
+                 C.F.R. 12.212 and 48 C.F.R. 227.7202-1 through 227.7202-4 (June 1995),
+                 all U.S. Government End Users acquire Covered Code with only those
+                 rights set forth herein.
+
+            11. MISCELLANEOUS.
+
+                 This License represents the complete agreement concerning subject
+                 matter hereof. If any provision of this License is held to be
+                 unenforceable, such provision shall be reformed only to the extent
+                 necessary to make it enforceable. This License shall be governed by
+                 California law provisions (except to the extent applicable law, if
+                 any, provides otherwise), excluding its conflict-of-law provisions.
+                 With respect to disputes in which at least one party is a citizen of,
+                 or an entity chartered or registered to do business in the United
+                 States of America, any litigation relating to this License shall be
+                 subject to the jurisdiction of the Federal Courts of the Northern
+                 District of California, with venue lying in Santa Clara County,
+                 California, with the losing party responsible for costs, including
+                 without limitation, court costs and reasonable attorneys' fees and
+                 expenses. The application of the United Nations Convention on
+                 Contracts for the International Sale of Goods is expressly excluded.
+                 Any law or regulation which provides that the language of a contract
+                 shall be construed against the drafter shall not apply to this
+                 License.
+
+            12. RESPONSIBILITY FOR CLAIMS.
+
+                 As between Initial Developer and the Contributors, each party is
+                 responsible for claims and damages arising, directly or indirectly,
+                 out of its utilization of rights under this License and You agree to
+                 work with Initial Developer and Contributors to distribute such
+                 responsibility on an equitable basis. Nothing herein is intended or
+                 shall be deemed to constitute any admission of liability.
+
+            13. MULTIPLE-LICENSED CODE.
+
+                 Initial Developer may designate portions of the Covered Code as
+                 "Multiple-Licensed".  "Multiple-Licensed" means that the Initial
+                 Developer permits you to utilize portions of the Covered Code under
+                 Your choice of the NPL or the alternative licenses, if any, specified
+                 by the Initial Developer in the file described in Exhibit A.
+
+            EXHIBIT A -Mozilla Public License.
+
+                 ``The contents of this file are subject to the Mozilla Public License
+                 Version 1.1 (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.mozilla.org/MPL/
+
+                 Software distributed under the License is distributed on an "AS IS"
+                 basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the
+                 License for the specific language governing rights and limitations
+                 under the License.
+
+                 The Original Code is RabbitMQ.
+
+                 The Initial Developer of the Original Code is VMware, Ltd..
+                 Portions created by VMware, Ltd. are Copyright (C)
+                 2007-2012 VMware, Inc.. All Rights Reserved.
+
+                 Contributor(s): .
+
+                 Alternatively, the contents of this file may be used under the terms
+                 of the GNU General Public License Version 2 license (the  "[GPL] License"), in which case the
+                 provisions of [GPL] License are applicable instead of those
+                 above.  If you wish to allow use of your version of this file only
+                 under the terms of the [GPL] License and not to allow others to use
+                 your version of this file under the MPL, indicate your decision by
+                 deleting  the provisions above and replace  them with the notice and
+                 other provisions required by the [GPL] License.  If you do not delete
+                 the provisions above, a recipient may use your version of this file
+                 under either the MPL or the [GPL] License."
+
+                 [NOTE: The text of this Exhibit A may differ slightly from the text of
+                 the notices in the Source Code files of the Original Code. You should
+                 use the text of this Exhibit A rather than the text found in the
+                 Original Code Source Code for Your Modifications.]
+
+
+        from VMware, Inc  http://www.vmware.com/
+            rabbitmq-client.jar  from http://www.rabbitmq.com/java-client.html
+
+
 Within the patches/systemvm/debian/config/etc directory
     placed in the public domain
         by Adiscon GmbH  http://www.adiscon.com/ 
@@ -2980,7 +3462,7 @@
             
             The Covered Software is a "commercial item," as that term is
             defined in 48 C.F.R. 2.101 (Oct. 1995), consisting of "commercial
-            computer software" (as that term is defined at 48 C.F.R. ¤
+            computer software" (as that term is defined at 48 C.F.R. �
             252.227-7014(a)(1)) and "commercial computer software
             documentation" as such terms are used in 48 C.F.R. 12.212 (Sept.
             1995). Consistent with 48 C.F.R. 12.212 and 48 C.F.R. 227.7202-1
@@ -3369,7 +3851,7 @@
             
             The Covered Software is a "commercial item," as that term is
             defined in 48 C.F.R. 2.101 (Oct. 1995), consisting of "commercial
-            computer software" (as that term is defined at 48 C.F.R. ¤
+            computer software" (as that term is defined at 48 C.F.R. �
             252.227-7014(a)(1)) and "commercial computer software
             documentation" as such terms are used in 48 C.F.R. 12.212 (Sept.
             1995). Consistent with 48 C.F.R. 12.212 and 48 C.F.R. 227.7202-1
@@ -3895,7 +4377,7 @@
 
     licensed under the MIT License http://www.opensource.org/licenses/mit-license.php  (as follows)
 
-            Copyright (C) 2008      Tóth István <stoty@tvnet.hu>
+            Copyright (C) 2008      T�th Istv�n <stoty@tvnet.hu>
                           2008-2012 Daniel Veillard <veillard@redhat.com>
                           2009-2011 Bryan Kearney <bkearney@redhat.com> 
             
@@ -4026,7 +4508,7 @@
 
     licensed under the MIT License http://www.opensource.org/licenses/mit-license.php  (as follows)
 
-            Copyright (c) 2006 - 2011 Jörn Zaefferer 
+            Copyright (c) 2006 - 2011 J�rn Zaefferer
             
             Permission is hereby granted, free  of charge, to any person obtaining
             a  copy  of this  software  and  associated  documentation files  (the
@@ -4221,7 +4703,7 @@
 Within the ui/lib/qunit directory
     licensed under the MIT License http://www.opensource.org/licenses/mit-license.php  (as follows)
 
-            Copyright (c) 2012 John Resig, Jörn Zaefferer 
+            Copyright (c) 2012 John Resig, J�rn Zaefferer
             
             Permission is hereby granted, free  of charge, to any person obtaining
             a  copy  of this  software  and  associated  documentation files  (the
diff --git a/tools/whisker/descriptor-for-packaging.xml b/tools/whisker/descriptor-for-packaging.xml
index 0144dbc..29a8284 100644
--- a/tools/whisker/descriptor-for-packaging.xml
+++ b/tools/whisker/descriptor-for-packaging.xml
@@ -2423,6 +2423,10 @@
             id='adiscon.com'
             name='Adiscon GmbH'
             url='http://www.adiscon.com/' />
+        <organisation
+            id='vmware.com'
+            name='VMware, Inc'
+            url='http://www.vmware.com/' />
     </organisations>
     <primary-license id='ApacheLicenseVersion2'>
         <copyright-notice>Copyright (c) 2013 The Apache Software Foundation</copyright-notice>
@@ -2948,5 +2952,19 @@
                    <resource name='javassist-3.9.0.GA.jar' source='http://sourceforge.net/projects/jboss/files/Javassist/' />
                </by-organisation>
         </with-license>
+        <with-license id='MPL1'>
+            <copyright-notice>Copyright (c) 2007-2012 VMware, Inc.  All Rights Reserved.</copyright-notice>
+            <license-parameters>
+                <parameter><name>PROJECT</name><value>RabbitMQ</value></parameter>
+                <parameter><name>INITIAL_DEVELOPER</name><value>VMware, Ltd.</value></parameter>
+                <parameter><name>INITIAL_DEVELOPER_COPYRIGHT</name><value>2007-2012 VMware, Inc.</value></parameter>
+                <parameter><name>CONTRIBUTORS</name><value></value></parameter>
+                <parameter><name>ALT_LIC_NAME</name><value>GNU General Public License Version 2</value></parameter>
+                <parameter><name>ALT_LIC_SHORT</name><value>GPL</value></parameter>
+               </license-parameters>
+               <by-organisation id='vmware.com'>
+                   <resource name='rabbitmq-client.jar' source='http://www.rabbitmq.com/java-client.html' />
+               </by-organisation>
+        </with-license>
     </within>
 </manifest>