// 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.network.contrail.management; import java.lang.reflect.Method; import java.util.HashMap; import javax.inject.Inject; import org.apache.log4j.Logger; import org.springframework.stereotype.Component; import org.apache.cloudstack.framework.messagebus.MessageBus; import org.apache.cloudstack.framework.messagebus.MessageDispatcher; import org.apache.cloudstack.framework.messagebus.MessageHandler; import com.cloud.domain.DomainVO; import com.cloud.domain.dao.DomainDao; import com.cloud.event.EventTypes; import com.cloud.offerings.dao.NetworkOfferingDao; import com.cloud.projects.ProjectVO; import com.cloud.projects.dao.ProjectDao; /* * When an Object is created/deleted in cloudstack DB, it has to be reflected in VNC. * This class handles create, delete and update events of cloudstack db objects. * * - subscribe for interested events * - create events will have db id of the object and hence db object and its parameters can be retrieved * - delete events will have db id but the object no longer exists in db and hence complete class needs to be synchronized * */ @Component public class ServerEventHandlerImpl implements ServerEventHandler { @Inject NetworkOfferingDao _networkOfferingDao; @Inject DomainDao _domainDao; @Inject ProjectDao _projectDao; @Inject private MessageBus _messageBus; @Inject ServerDBSync _dbSync; @Inject ContrailManager _manager; private HashMap<String, Method> _methodMap; private HashMap<String, Class<?>> _classMap; private static final Logger s_logger = Logger.getLogger(MessageHandler.class); ServerEventHandlerImpl() { setMethodMap(); setClassMap(); } private void setMethodMap() { _methodMap = new HashMap<String, Method>(); Method methods[] = this.getClass().getMethods(); for (int i = 0; i < methods.length; i++) { _methodMap.put(methods[i].getName(), methods[i]); } } private void setClassMap() { _classMap = new HashMap<String, Class<?>>(); _classMap.put("Domain", net.juniper.contrail.api.types.Domain.class); _classMap.put("Project", net.juniper.contrail.api.types.Project.class); } @MessageHandler(topic = ".*") public void defaultMessageHandler(String subject, String topic, Object args) { s_logger.info("DB Event Received - topic: " + topic + "; subject: " + subject); org.apache.cloudstack.framework.events.Event event = (org.apache.cloudstack.framework.events.Event)args; /* Method name should be on<ClassName><Operation> for example: onDomainCreate */ Method method = null; try { /* Only create event needs special implementation */ if (event.getEventType().contains("CREATE")) { String methodName = "on" + event.getResourceType() + "Create"; method = _methodMap.get(methodName); if (method == null) { defaultCreateHandler(subject, topic, event); } else { method.invoke(this, subject, topic, event); } } else if (event.getEventType().contains("DELETE")) { defaultDeleteHandler(subject, topic, event); } else { defaultHandler(subject, topic, event); } } catch (Exception e) { s_logger.debug(e); } } /* Default create handler */ void defaultCreateHandler(String subject, String topic, org.apache.cloudstack.framework.events.Event event) { s_logger.debug("Default handler is invoked for subject: " + subject + "; topic: " + topic); s_logger.debug("description: " + event.getDescription()); s_logger.debug("category: " + event.getEventCategory()); s_logger.debug("type: " + event.getResourceType()); s_logger.debug("event-type: " + event.getEventType()); Class<?> cls = _classMap.get(event.getResourceType()); if (cls != null) { _dbSync.syncClass(cls); } return; } /* Default handler */ void defaultDeleteHandler(String subject, String topic, org.apache.cloudstack.framework.events.Event event) { s_logger.debug("Default handler is invoked for subject: " + subject + "; topic: " + topic); s_logger.debug("description: " + event.getDescription()); s_logger.debug("category: " + event.getEventCategory()); s_logger.debug("type: " + event.getResourceType()); s_logger.debug("event-type: " + event.getEventType()); Class<?> cls = _classMap.get(event.getResourceType()); if (cls != null) { _dbSync.syncClass(cls); } return; } /* Default handler */ void defaultHandler(String subject, String topic, org.apache.cloudstack.framework.events.Event event) { s_logger.debug("Default handler is invoked for subject: " + subject + "; topic: " + topic); s_logger.debug("description: " + event.getDescription()); s_logger.debug("category: " + event.getEventCategory()); s_logger.debug("type: " + event.getResourceType()); s_logger.debug("event-type: " + event.getEventType()); Class<?> cls = _classMap.get(event.getResourceType()); if (cls != null) { _dbSync.syncClass(cls); } return; } /* Description string contains substring of format "resourceType Id: <int>" for example: "Project id: 35" * * example: * description: {"details":"Successfully completed deleting project. Project Id: 39","status":"Completed","event":"PROJECT.DELETE","account":"3afca502-d83c-11e2-b748-52540076b7ca","user":"3b111406-d83c-11e2-b748-52540076b7ca"} * * If the description string format is changed, this code has to be modified */ private long parseForId(String resourceType, String description) { String typeStr = resourceType + " Id:"; int idIdx = description.indexOf(typeStr) + typeStr.length(); String idStr = description.substring(idIdx, description.indexOf('"', idIdx)); long id = 0; try { id = Long.parseLong(idStr.trim()); } catch (Exception e) { s_logger.debug("Unable to parse id string<" + idStr.trim() + "> for long value, ignored"); } return id; } public void onDomainCreate(String subject, String topic, org.apache.cloudstack.framework.events.Event event) { s_logger.info("onDomainCreate; topic: " + topic + "; subject: " + subject); try { long id = parseForId(event.getResourceType(), event.getDescription()); if (id != 0) { DomainVO domain = _domainDao.findById(id); if (domain != null) { s_logger.info("createDomain for name: " + domain.getName() + "; uuid: " + domain.getUuid()); StringBuffer logMesg = new StringBuffer(); _dbSync.createDomain(domain, logMesg); } else { /* could not find db record, resync complete class */ _dbSync.syncClass(net.juniper.contrail.api.types.Domain.class); } } else { /* Unknown id, resync complete class */ _dbSync.syncClass(net.juniper.contrail.api.types.Domain.class); } } catch (Exception e) { s_logger.debug(e); } } public void onProjectCreate(String subject, String topic, org.apache.cloudstack.framework.events.Event event) { s_logger.info("onProjectCreate; topic: " + topic + "; subject: " + subject); try { long id = parseForId(event.getResourceType(), event.getDescription()); if (id != 0) { ProjectVO project = _projectDao.findById(id); if (project != null) { s_logger.info("createProject for name: " + project.getName() + "; uuid: " + project.getUuid()); StringBuffer logMesg = new StringBuffer(); _dbSync.createProject(project, logMesg); } else { /* could not find db record, resync complete class */ _dbSync.syncClass(net.juniper.contrail.api.types.Project.class); } } else { /* Unknown id, resync complete class */ _dbSync.syncClass(net.juniper.contrail.api.types.Project.class); } } catch (Exception e) { s_logger.info(e); } } @Override public void subscribe() { /* subscribe to DB events */ _messageBus.subscribe(EventTypes.EVENT_PROJECT_CREATE, MessageDispatcher.getDispatcher(this)); _messageBus.subscribe(EventTypes.EVENT_PROJECT_DELETE, MessageDispatcher.getDispatcher(this)); _messageBus.subscribe(EventTypes.EVENT_DOMAIN_CREATE, MessageDispatcher.getDispatcher(this)); _messageBus.subscribe(EventTypes.EVENT_DOMAIN_DELETE, MessageDispatcher.getDispatcher(this)); } }