/******************************************************************************* * This file is part of OpenNMS(R). * * Copyright (C) 2009-2011 The OpenNMS Group, Inc. * OpenNMS(R) is Copyright (C) 1999-2011 The OpenNMS Group, Inc. * * OpenNMS(R) is a registered trademark of The OpenNMS Group, Inc. * * OpenNMS(R) is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published * by the Free Software Foundation, either version 3 of the License, * or (at your option) any later version. * * OpenNMS(R) is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with OpenNMS(R). If not, see: * http://www.gnu.org/licenses/ * * For more information contact: * OpenNMS(R) Licensing <license@opennms.org> * http://www.opennms.org/ * http://www.opennms.com/ *******************************************************************************/ package org.opennms.netmgt.provision; import static org.opennms.core.utils.InetAddressUtils.str; import java.util.ArrayList; import java.util.Collection; import java.util.Date; import java.util.List; import java.util.Map; import java.util.Set; import java.util.TreeSet; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; import java.util.regex.Matcher; import java.util.regex.Pattern; import org.opennms.core.utils.LogUtils; import org.opennms.core.utils.ThreadCategory; import org.opennms.netmgt.EventConstants; import org.opennms.netmgt.config.MapsAdapterConfig; import org.opennms.netmgt.config.MapsAdapterConfigFactory; import org.opennms.netmgt.config.map.adapter.Celement; import org.opennms.netmgt.config.map.adapter.Cmap; import org.opennms.netmgt.config.map.adapter.Csubmap; import org.opennms.netmgt.dao.NodeDao; import org.opennms.netmgt.dao.OnmsMapDao; import org.opennms.netmgt.dao.OnmsMapElementDao; import org.opennms.netmgt.model.OnmsIpInterface; import org.opennms.netmgt.model.OnmsMap; import org.opennms.netmgt.model.OnmsMapElement; import org.opennms.netmgt.model.OnmsNode; import org.opennms.netmgt.model.events.EventBuilder; import org.opennms.netmgt.model.events.EventForwarder; import org.opennms.netmgt.model.events.annotations.EventHandler; import org.opennms.netmgt.model.events.annotations.EventListener; import org.opennms.netmgt.xml.event.Event; import org.opennms.netmgt.xml.event.Parm; import org.springframework.beans.factory.InitializingBean; import org.springframework.transaction.TransactionStatus; import org.springframework.transaction.support.TransactionCallback; import org.springframework.transaction.support.TransactionTemplate; import org.springframework.util.Assert; /** * A Dynamic Map provisioning adapter for integration with OpenNMS Provisioning daemon API. * * @author <a href="mailto:antonio@opennms.it">Antonio Russo</a> * @version $Id: $ */ @EventListener(name="MapsProvisioningAdapter") public class MapProvisioningAdapter extends SimpleQueuedProvisioningAdapter implements InitializingBean { private class XY { int x; int y; protected XY(){ } public int getX() { return x; } public void setX(int x) { this.x = x; } public int getY() { return y; } public void setY(int y) { this.y = y; } } private XY getXY(OnmsMap map, int mapElementSize) { int deltaX = m_mapsAdapterConfig.getMapElementDimension(); int deltaY = deltaX/2; int maxNumberofelementsonX=map.getWidth()/(2*deltaX); log().debug("getXY: max number of elements on a row: " +maxNumberofelementsonX); int numberofexistingelement = mapElementSize; log().debug("getXY: number of existing elements on map: " + mapElementSize); int positiononX = 1; int positiononY = 1; boolean addoffset = true; while (maxNumberofelementsonX <= numberofexistingelement){ numberofexistingelement = numberofexistingelement - maxNumberofelementsonX; log().debug("getXY: entering the loop: element found on the row: " + numberofexistingelement); positiononY++; if (addoffset) { maxNumberofelementsonX--; } else { maxNumberofelementsonX++; } addoffset = !addoffset; } positiononX = positiononX + numberofexistingelement; XY xy = new XY(); if (addoffset) { xy.setX(2*deltaX*positiononX-deltaX); } else { xy.setX(2*deltaX*positiononX); } xy.setY(deltaY*positiononY); return xy; } private Object m_lock = new Object(); private NodeDao m_onmsNodeDao; private OnmsMapDao m_onmsMapDao; private OnmsMapElementDao m_onmsMapElementDao; private EventForwarder m_eventForwarder; private MapsAdapterConfig m_mapsAdapterConfig; private TransactionTemplate m_template; private volatile static ConcurrentMap<String,Integer> m_mapNameMapSizeListMap; private static final String MESSAGE_PREFIX = "Dynamic Map provisioning failed: "; private static final String ADAPTER_NAME="MAP Provisioning Adapter"; private static final long RESYNC_TIMEOUT=300000; private Set<Integer> m_deletes; private Set<Integer> m_adds; private Set<Integer> m_updates; private boolean doSync = false; /** * <p>getOnmsMapDao</p> * * @return a {@link org.opennms.netmgt.dao.OnmsMapDao} object. */ public OnmsMapDao getOnmsMapDao() { return m_onmsMapDao; } /** * <p>setOnmsMapDao</p> * * @param onmsMapDao a {@link org.opennms.netmgt.dao.OnmsMapDao} object. */ public void setOnmsMapDao(OnmsMapDao onmsMapDao) { m_onmsMapDao = onmsMapDao; } /** * <p>getOnmsMapElementDao</p> * * @return a {@link org.opennms.netmgt.dao.OnmsMapElementDao} object. */ public OnmsMapElementDao getOnmsMapElementDao() { return m_onmsMapElementDao; } /** * <p>setOnmsMapElementDao</p> * * @param onmsMapElementDao a {@link org.opennms.netmgt.dao.OnmsMapElementDao} object. */ public void setOnmsMapElementDao(OnmsMapElementDao onmsMapElementDao) { m_onmsMapElementDao = onmsMapElementDao; } /** * <p>getMapsAdapterConfig</p> * * @return a {@link org.opennms.netmgt.config.MapsAdapterConfig} object. */ public MapsAdapterConfig getMapsAdapterConfig() { return m_mapsAdapterConfig; } /** * <p>setMapsAdapterConfig</p> * * @param mapsAdapterConfig a {@link org.opennms.netmgt.config.MapsAdapterConfig} object. */ public void setMapsAdapterConfig(MapsAdapterConfig mapsAdapterConfig) { m_mapsAdapterConfig = mapsAdapterConfig; } /** * <p>setEventForwarder</p> * * @param eventForwarder a {@link org.opennms.netmgt.model.events.EventForwarder} object. */ public void setEventForwarder(EventForwarder eventForwarder) { m_eventForwarder = eventForwarder; } /** * <p>getEventForwarder</p> * * @return a {@link org.opennms.netmgt.model.events.EventForwarder} object. */ public EventForwarder getEventForwarder() { return m_eventForwarder; } /** * <p>getOnmsNodeDao</p> * * @return a {@link org.opennms.netmgt.dao.NodeDao} object. */ public NodeDao getOnmsNodeDao() { return m_onmsNodeDao; } /** * <p>setOnmsNodeDao</p> * * @param onmsNodeDao a {@link org.opennms.netmgt.dao.NodeDao} object. */ public void setOnmsNodeDao(NodeDao onmsNodeDao) { m_onmsNodeDao = onmsNodeDao; } /** * <p>getTemplate</p> * * @return a {@link org.springframework.transaction.support.TransactionTemplate} object. */ public TransactionTemplate getTemplate() { return m_template; } /** * <p>setTemplate</p> * * @param template a {@link org.springframework.transaction.support.TransactionTemplate} object. */ public void setTemplate(TransactionTemplate template) { m_template = template; } private static ThreadCategory log() { return ThreadCategory.getInstance(MapProvisioningAdapter.class); } /** * <p>handleReloadConfigEvent</p> * * @param event a {@link org.opennms.netmgt.xml.event.Event} object. */ @EventHandler(uei = EventConstants.RELOAD_DAEMON_CONFIG_UEI) public void handleReloadConfigEvent(Event event) { if (isReloadConfigEventTarget(event)) { LogUtils.debugf(this, "reloading the maps adapter configuration"); try { MapsAdapterConfigFactory.reload(); syncMaps(); } catch (Throwable e) { LogUtils.infof(this, e, "unable to reload maps adapter configuration"); } } } private boolean isReloadConfigEventTarget(Event event) { boolean isTarget = false; List<Parm> parmCollection = event.getParmCollection(); for (Parm parm : parmCollection) { if (EventConstants.PARM_DAEMON_NAME.equals(parm.getParmName()) && "Provisiond.MapProvisioningAdapter".equalsIgnoreCase(parm.getValue().getContent())) { isTarget = true; break; } } log().debug("isReloadConfigEventTarget: Provisiond.MapProvisioningAdapter was target of reload event: " + isTarget); return isTarget; } /** * <p>getName</p> * * @return a {@link java.lang.String} object. */ public String getName() { return ADAPTER_NAME; } /** {@inheritDoc} */ @Override public boolean isNodeReady(AdapterOperation op) { return true; } class MapSyncExecutor implements Runnable { public void run() { syncMaps(); while (true) { try { log().debug("Sleeping: " + RESYNC_TIMEOUT); Thread.sleep(RESYNC_TIMEOUT); } catch (InterruptedException e) { log().error("Cannot sleep:" + e.getLocalizedMessage()); } if (doSync) { log().debug("Synchronization started"); Set<Integer> deletes = new TreeSet<Integer>(); Set<Integer> adds = new TreeSet<Integer>(); Set<Integer> updates = new TreeSet<Integer>(); log().info("acquiring lock..."); synchronized (m_lock) { for (Integer i: m_deletes) { deletes.add(i); } for (Integer i: m_adds) { adds.add(i); } for (Integer i: m_updates) { updates.add(i); } m_deletes = new TreeSet<Integer>(); m_updates = new TreeSet<Integer>(); m_adds = new TreeSet<Integer>(); doSync = false; } log().info("lock released."); reSyncMap(deletes,adds,updates); } else { log().debug("No Synchronization required"); } } } } /** {@inheritDoc} */ @Override public void processPendingOperationForNode(AdapterOperation op) throws ProvisioningAdapterException { log().info("processPendingOperationsForNode: acquiring lock..."); synchronized (m_lock) { log().debug("processPendingOperationForNode: processing operation: " + op.getType().name() + " for node with Id: #" + op.getNodeId()); if (op.getType() == AdapterOperationType.ADD) { m_adds.add(op.getNodeId()); } else if (op.getType() == AdapterOperationType.UPDATE) { m_updates.add(op.getNodeId()); } else if (op.getType() == AdapterOperationType.DELETE) { m_deletes.add(op.getNodeId()); } doSync=true; } log().info("processPendingOperationsForNode: lock released."); } private void reSyncMap(final Set<Integer> deletes,final Set<Integer> adds,final Set<Integer> updates) throws ProvisioningAdapterException { m_mapsAdapterConfig.rebuildPackageIpListMap(); m_template.execute(new TransactionCallback<Object>() { public Object doInTransaction(TransactionStatus arg0) { try { // first of all delete the element with nodeid ind deletes for (Integer nodeid: deletes) { log().debug("reSyncMap: deleting map element with nodeid: " + nodeid); m_onmsMapElementDao.deleteElementsByNodeid(nodeid); } // skip operation if there are only deletes if (adds.isEmpty() && updates.isEmpty()) return null; Map<String,OnmsMap> mapNames= new ConcurrentHashMap<String,OnmsMap>(m_mapNameMapSizeListMap.size()); for (OnmsMap onmsMap : m_onmsMapDao.findAutoAndSaveMaps()) { if ( m_mapNameMapSizeListMap.containsKey(onmsMap.getName()) || onmsMap.getType().equals(OnmsMap.AUTOMATIC_SAVED_MAP)) { log().debug("reSyncMaps: fetching map from db: " +onmsMap.getName() + " type: " + onmsMap.getType()); mapNames.put(onmsMap.getName(), onmsMap); } } for(Integer nodeid: adds) { log().debug("reSyncMap: adding map elements with nodeid: " + nodeid); if (deletes.contains(nodeid)) { log().debug("reSyncMap: skipping because was deleted"); continue; } if (updates.contains(nodeid)) { log().debug("reSyncMap: skipping because was updated"); continue; } OnmsNode node = m_onmsNodeDao.get(nodeid); Map<String, Celement> mapNameCelements = m_mapsAdapterConfig.getElementByAddress(getSuitableIp(node)); for (String mapName: mapNameCelements.keySet()) { log().debug("reSyncMap: add: found container map: " + mapName); if (!mapNames.containsKey(mapName)) { log().debug("reSyncMap: map: " + mapName + " not in database. skipping...."); continue; } Celement celement = mapNameCelements.get(mapName); OnmsMap onmsMap = mapNames.get(mapName); if (onmsMap.getType().equals(OnmsMap.AUTOMATICALLY_GENERATED_MAP)) { log().debug("reSyncMap: adding node: " + node.getLabel() + " to map: " + mapName); int elementsize = m_mapNameMapSizeListMap.get(mapName); log().debug("reSyncMap: mapElement is new: found last mapElement at position #" + elementsize + " on map: " + mapName); XY xy=getXY(onmsMap, elementsize); log().debug("reSyncMaps: mapElement is new: saved last mapElement at X position: " + xy.getX()); log().debug("reSyncMap: mapElement is new: saved last mapElement at Y position: " + xy.getY()); m_onmsMapElementDao.save( new OnmsMapElement(onmsMap,node.getId(),OnmsMapElement.NODE_TYPE,getLabel(node.getLabel()),celement.getIcon(),xy.getX(),xy.getY()) ); m_mapNameMapSizeListMap.replace(mapName, ++elementsize); } else { m_onmsMapElementDao.save( new OnmsMapElement(onmsMap,node.getId(),OnmsMapElement.NODE_HIDE_TYPE,getLabel(node.getLabel()),celement.getIcon(),0,0) ); } m_onmsMapElementDao.flush(); } } // end add nodes loop for(Integer nodeid: updates) { log().debug("reSyncMap: updating map elements with nodeid: " + nodeid); if (deletes.contains(nodeid)) { log().debug("reSyncMap: skipping because was deleted"); continue; } OnmsNode node = m_onmsNodeDao.get(nodeid); Collection<OnmsMapElement> elements = m_onmsMapElementDao.findElementsByNodeId(nodeid); Map<String, Celement> mapNameCelements = m_mapsAdapterConfig.getElementByAddress(getSuitableIp(node)); for (String mapName: mapNameCelements.keySet()) { log().debug("reSyncMap: update: found container map: " + mapName); if (!mapNames.containsKey(mapName)) { log().debug("reSyncMap: map: " + mapName + " not in database. skipping...."); continue; } Celement celement = mapNameCelements.get(mapName); OnmsMap onmsMap = mapNames.get(mapName); Collection<OnmsMapElement> tempElem = new ArrayList<OnmsMapElement>(); boolean elementExist = false; for (OnmsMapElement elem: elements) { if (elem.getMap().getId() == onmsMap.getId() ) { elementExist = true; String label = getLabel(node.getLabel()); if (elem.getLabel().equals(label)) { log().debug("reSyncMap: nodeid: " + nodeid + " is in map:" + mapName + " and has the same label. skipping..."); } else { log().debug("reSyncMap: nodeid: " + nodeid + " is in map:" + mapName + " and has not the same label. updating..."); elem.setLabel(label); m_onmsMapElementDao.update(elem); } continue; } tempElem.add(elem); } elements = tempElem; if (elementExist) continue; if (onmsMap.getType().equals(OnmsMap.AUTOMATICALLY_GENERATED_MAP)) { log().debug("reSyncMap: adding node: " + node.getLabel() + " to map: " + mapName); int elementsize = m_mapNameMapSizeListMap.get(mapName); log().debug("reSyncMap: mapElement is new: found last mapElement at position #" + elementsize + " on map: " + mapName); XY xy=getXY(onmsMap, elementsize); log().debug("reSyncMaps: mapElement is new: saved last mapElement at X position: " + xy.getX()); log().debug("reSyncMap: mapElement is new: saved last mapElement at Y position: " + xy.getY()); m_onmsMapElementDao.save( new OnmsMapElement(onmsMap,node.getId(),OnmsMapElement.NODE_TYPE,getLabel(node.getLabel()),celement.getIcon(),xy.getX(),xy.getY()) ); m_mapNameMapSizeListMap.replace(mapName, ++elementsize); } else { m_onmsMapElementDao.save( new OnmsMapElement(onmsMap,node.getId(),OnmsMapElement.NODE_HIDE_TYPE,getLabel(node.getLabel()),celement.getIcon(),0,0) ); } m_onmsMapElementDao.flush(); } // delete elements from automated map for(OnmsMapElement element: elements) { if (element.getMap().getType().equals(OnmsMap.AUTOMATICALLY_GENERATED_MAP)) m_onmsMapElementDao.delete(element); } } // end updates loop // add not empty map and remove empty submap Map<String,List<Csubmap>> mapnameSubmapMap = m_mapsAdapterConfig.getsubMaps(); Map<String,Integer> mapNameSizeMap = new ConcurrentHashMap<String, Integer>(); for (String mapName : mapnameSubmapMap.keySet()) { log().debug("reSyncMap: update sub maps: found container map: " + mapName); if (!mapNames.containsKey(mapName)) { log().debug("reSyncMap: map: " + mapName + " not in database. skipping...."); continue; } OnmsMap onmsMap = mapNames.get(mapName); log().debug("reSyncMaps: map type: " + onmsMap.getType()); boolean auto; Collection<OnmsMapElement> elements = m_onmsMapElementDao.findElementsByMapIdAndType(onmsMap.getId(), OnmsMapElement.MAP_TYPE); if (onmsMap.getType().equals(OnmsMap.AUTOMATICALLY_GENERATED_MAP)) { auto = true; } else if (onmsMap.getType().equals(OnmsMap.AUTOMATIC_SAVED_MAP)) { auto = false; elements.addAll(m_onmsMapElementDao.findElementsByMapIdAndType(onmsMap.getId(), OnmsMapElement.MAP_HIDE_TYPE)); } else { log().debug("reSyncMaps: cannot add submaps to map: " + mapName); continue; } // loop on submaps for (Csubmap csubmap : mapnameSubmapMap.get(mapName)) { log().debug("reSyncMaps: submap: " + csubmap.getName()); if (! mapNames.containsKey(csubmap.getName())) { log().debug("reSyncMap: map: " + csubmap.getName() + " not in database. skipping...."); continue; } OnmsMap onmsSubMap = mapNames.get(csubmap.getName()); if (!mapNameSizeMap.containsKey(onmsSubMap.getName())) { mapNameSizeMap.put(csubmap.getName(), m_onmsMapElementDao.countElementsOnMap(onmsSubMap.getId())); } //Loop to verify if the map exists Collection<OnmsMapElement> tempelems = new ArrayList<OnmsMapElement>(); OnmsMapElement foundelement= null; for (OnmsMapElement element: elements) { if (element.getElementId() == onmsSubMap.getId()){ foundelement=element; log().debug("reSyncMap: map with id: " + onmsSubMap.getId() + " is in map:" + mapName + "."); continue; } tempelems.add(element); } elements = tempelems; if ( (!csubmap.getAddwithoutelements()) && mapNameSizeMap.get(csubmap.getName())==0) { if (foundelement != null && (auto|| foundelement.getType().equals(OnmsMapElement.MAP_HIDE_TYPE))) m_onmsMapElementDao.delete(foundelement); continue; } if (foundelement != null) continue; log().debug("ReSyncMaps: add submap: " + csubmap.getName() + "to map: " + mapName); if (auto) { XY xy = new XY(); if (csubmap.hasX() && csubmap.hasY()) { xy.setX(csubmap.getX()); xy.setY(csubmap.getY()); } else { int elementsize = m_mapNameMapSizeListMap.get(mapName); xy=getXY(onmsMap, elementsize); m_mapNameMapSizeListMap.replace(mapName, ++elementsize); } m_onmsMapElementDao.save(new OnmsMapElement(onmsMap,onmsSubMap.getId(),OnmsMapElement.MAP_TYPE,csubmap.getLabel(),csubmap.getIcon(),xy.getX(),xy.getY())); } else { m_onmsMapElementDao.save(new OnmsMapElement(onmsMap,onmsSubMap.getId(),OnmsMapElement.MAP_HIDE_TYPE,csubmap.getLabel(),csubmap.getIcon(),0,0)); } m_onmsMapElementDao.flush(); } } int i = m_onmsMapDao.updateAllAutomatedMap(new Date()); log().debug("reSyncMap: updated last modified time for automated map: row#: " + i); } catch (Throwable e) { log().error(e.getMessage()); sendAndThrow(e); } return null; } }); } /** * <p>afterPropertiesSet</p> * * @throws java.lang.Exception if any. */ @Override public void afterPropertiesSet() throws Exception { Assert.notNull(m_onmsNodeDao, "Map Provisioning Adapter requires nodeDao property to be set."); Assert.notNull(m_onmsMapDao, "Map Provisioning Adapter requires OnmsMapDao property to be set."); Assert.notNull(m_onmsMapElementDao, "Map Provisioning Adapter requires OnmsMapElementDao property to be set."); Assert.notNull(m_mapsAdapterConfig, "Map Provisioning Adapter requires MapasAdapterConfig property to be set."); Assert.notNull(m_eventForwarder, "Map Provisioning Adapter requires EventForwarder property to be set."); m_deletes = new TreeSet<Integer>(); m_updates = new TreeSet<Integer>(); m_adds = new TreeSet<Integer>(); } /** {@inheritDoc} */ @Override public void init() throws ProvisioningAdapterException { MapSyncExecutor e = new MapSyncExecutor(); new Thread(e, MapSyncExecutor.class.getSimpleName()).start(); } private void syncMaps() throws ProvisioningAdapterException { try { m_template.execute(new TransactionCallback<Object>() { public Object doInTransaction(TransactionStatus arg0) { log().info("syncMaps: acquiring lock..."); synchronized (m_lock) { log().debug("syncMaps: lock acquired. syncing maps..."); m_mapsAdapterConfig.getReadLock().lock(); try { final List<Cmap> cmaps = m_mapsAdapterConfig.getAllMaps(); m_mapNameMapSizeListMap = new ConcurrentHashMap<String, Integer>(cmaps.size()); final Map<String,OnmsMap> mapNames= new ConcurrentHashMap<String,OnmsMap>(cmaps.size()); for (Cmap cmap: cmaps) { final OnmsMap onmsMap = new OnmsMap(); onmsMap.setName(cmap.getMapName()); onmsMap.setType(OnmsMap.AUTOMATICALLY_GENERATED_MAP); mapNames.put(cmap.getMapName(),onmsMap); } final Date now = new Date(); log().debug("syncMaps: sync automated and static maps in database with configuration"); log().debug("syncMaps: deleting elements from automated existing map: "); m_onmsMapElementDao.deleteElementsByMapType(OnmsMap.AUTOMATICALLY_GENERATED_MAP); m_onmsMapElementDao.deleteElementsByType(OnmsMapElement.MAP_HIDE_TYPE); m_onmsMapElementDao.deleteElementsByType(OnmsMapElement.NODE_HIDE_TYPE); for (final OnmsMap onmsMap : m_onmsMapDao.findAutoAndSaveMaps()) { if ( mapNames.containsKey(onmsMap.getName()) || onmsMap.getType().equals(OnmsMap.AUTOMATIC_SAVED_MAP)) { //Move a map from Static to User if its no longer in the mapsadapter-configuration.xml if(onmsMap.getType().equals(OnmsMap.AUTOMATIC_SAVED_MAP) && !mapNames.containsKey(onmsMap.getName())) { onmsMap.setType(OnmsMap.USER_GENERATED_MAP); } log().debug("syncMaps: fetching map from db: " +onmsMap.getName() + " type: " + onmsMap.getType()); mapNames.put(onmsMap.getName(), onmsMap); } else { log().debug("syncMaps: deleting old automated map: " + onmsMap.getName()); log().debug("syncMaps: removing as map Element from all maps."); m_onmsMapElementDao.deleteElementsByElementIdAndType(onmsMap.getId(), OnmsMapElement.MAP_TYPE); log().debug("syncMaps: removing from map table."); m_onmsMapDao.delete(onmsMap); m_onmsMapElementDao.flush(); m_onmsMapDao.flush(); } } for (final Cmap cmap: cmaps) { final OnmsMap onmsMap = mapNames.get(cmap.getMapName()); if (onmsMap.getType().equals(OnmsMap.AUTOMATICALLY_GENERATED_MAP)) { log().debug("syncMaps: sync automated map: " + onmsMap.getName()); onmsMap.setOwner(cmap.getMapOwner()); onmsMap.setUserLastModifies(cmap.getMapOwner()); onmsMap.setMapGroup(cmap.getMapGroup()); onmsMap.setAccessMode(cmap.getMapAccess()); onmsMap.setBackground(cmap.getMapBG()); onmsMap.setHeight(cmap.getMapHeight()); onmsMap.setWidth(cmap.getMapWidth()); onmsMap.setLastModifiedTime(now); m_onmsMapDao.saveOrUpdate(onmsMap); m_mapNameMapSizeListMap.put(cmap.getMapName(),0); } else { log().debug("syncMaps: skipping not automated map: " + onmsMap.getName()); log().debug("syncMaps: map type: " + onmsMap.getType()); } m_onmsMapElementDao.flush(); } // adding nodes to auto maps for(final OnmsNode node: m_onmsNodeDao.findAllProvisionedNodes()) { log().debug("syncMaps: try to sync automated maps for node element: '" + node.getLabel() +"'"); final Map<String, Celement> mapNameCelements = m_mapsAdapterConfig.getElementByAddress(getSuitableIp(node)); for (final String mapName: mapNameCelements.keySet()) { final Celement celement = mapNameCelements.get(mapName); final OnmsMap onmsMap = mapNames.get(mapName); if (onmsMap.getType().equals(OnmsMap.AUTOMATICALLY_GENERATED_MAP)) { log().debug("syncMaps: adding node: " + node.getLabel() + " to map: " + mapName); int elementsize = m_mapNameMapSizeListMap.get(mapName); log().debug("syncMaps: mapElement is new: found last mapElement at position #" + elementsize + " on map: " + mapName); XY xy=getXY(onmsMap, elementsize); log().debug("syncMaps: mapElement is new: saved last mapElement at X position: " + xy.getX()); log().debug("syncMaps: mapElement is new: saved last mapElement at Y position: " + xy.getY()); m_onmsMapElementDao.save( new OnmsMapElement(onmsMap,node.getId(),OnmsMapElement.NODE_TYPE,getLabel(node.getLabel()),celement.getIcon(),xy.getX(),xy.getY()) ); m_mapNameMapSizeListMap.replace(mapName, ++elementsize); } else if (m_onmsMapElementDao.findElement(node.getId(), OnmsMapElement.NODE_TYPE, onmsMap) == null && m_onmsMapElementDao.findElement(node.getId(), OnmsMapElement.NODE_HIDE_TYPE, onmsMap) == null) { m_onmsMapElementDao.save( new OnmsMapElement(onmsMap,node.getId(),OnmsMapElement.NODE_HIDE_TYPE,getLabel(node.getLabel()),celement.getIcon(),0,0) ); } } } final Map<String,List<Csubmap>> submaps = m_mapsAdapterConfig.getsubMaps(); for (final String mapName : submaps.keySet()) { final OnmsMap onmsMap = mapNames.get(mapName); log().debug("syncMaps: found container map: " + mapName + " type: " + onmsMap.getType()); Collection<OnmsMapElement> elements = new ArrayList<OnmsMapElement>(); boolean auto; if (onmsMap.getType().equals(OnmsMap.AUTOMATICALLY_GENERATED_MAP)) { auto = true; } else if (onmsMap.getType().equals(OnmsMap.AUTOMATIC_SAVED_MAP)) { elements = m_onmsMapElementDao.findElementsByMapIdAndType(onmsMap.getId(), OnmsMapElement.MAP_TYPE); auto = false; } else { log().debug("syncMaps: cannot add submaps to map: " + mapName); continue; } SUBMAP: for (final Csubmap csubmap : submaps.get(mapName)) { final OnmsMap onmsSubMap = mapNames.get(csubmap.getName()); log().debug("syncMaps: add submap: " + csubmap.getName()); if ( (!csubmap.getAddwithoutelements()) && m_mapNameMapSizeListMap.get(csubmap.getName())==0) { continue; } log().debug("syncMaps: add submap: " + csubmap.getName() + "to map: " + mapName); if (auto) { XY xy = new XY(); if (csubmap.hasX() && csubmap.hasY()) { xy.setX(csubmap.getX()); xy.setY(csubmap.getY()); } else { int elementsize = m_mapNameMapSizeListMap.get(mapName); xy=getXY(onmsMap, elementsize); m_mapNameMapSizeListMap.replace(mapName, ++elementsize); } m_onmsMapElementDao.save(new OnmsMapElement(onmsMap,onmsSubMap.getId(),OnmsMapElement.MAP_TYPE,csubmap.getLabel(),csubmap.getIcon(),xy.getX(),xy.getY())); } else { for (final OnmsMapElement element: elements) { if (element.getElementId() == onmsSubMap.getId()) continue SUBMAP; } m_onmsMapElementDao.save(new OnmsMapElement(onmsMap,onmsSubMap.getId(),OnmsMapElement.MAP_HIDE_TYPE,csubmap.getLabel(),csubmap.getIcon(),0,0)); } } m_onmsMapElementDao.flush(); } log().debug("syncMaps: maps synchronized. releasing lock..."); } finally { m_mapsAdapterConfig.getReadLock().unlock(); } } log().info("syncMaps: lock released."); return null; } }); } catch (final Exception e) { log().error("syncMaps: Caught exception synchronizing maps: "+e, e); throw new ProvisioningAdapterException("syncMaps exception",e); } } private void sendAndThrow(final Throwable e) { final Event event = buildEvent(EventConstants.PROVISIONING_ADAPTER_FAILED).addParam("reason", MESSAGE_PREFIX+e.getLocalizedMessage()).getEvent(); m_eventForwarder.sendNow(event); log().error(e.getMessage()); throw new ProvisioningAdapterException(MESSAGE_PREFIX, e); } private EventBuilder buildEvent(final String uei) { return new EventBuilder(uei, "Provisioner", new Date()); } /** * <p>getSuitableIp</p> * * @param node a {@link org.opennms.netmgt.model.OnmsNode} object. * @return a {@link java.lang.String} object. */ public String getSuitableIp(final OnmsNode node){ final OnmsIpInterface primaryInterface = node.getPrimaryInterface(); if (primaryInterface == null) { final Set<OnmsIpInterface> ipInterfaces = node.getIpInterfaces(); for (final OnmsIpInterface onmsIpInterface : ipInterfaces) { return str(onmsIpInterface.getIpAddress()); } return "0.0.0.0"; } return str(primaryInterface.getIpAddress()); } private String getLabel(final String FQDN) { if (FQDN.indexOf(".")>0 && !validate(FQDN)) return FQDN.substring(0, FQDN.indexOf(".")); return FQDN; } private static final String IPADDRESS_PATTERN = "^([01]?\\d\\d?|2[0-4]\\d|25[0-5])\\." + "([01]?\\d\\d?|2[0-4]\\d|25[0-5])\\." + "([01]?\\d\\d?|2[0-4]\\d|25[0-5])\\." + "([01]?\\d\\d?|2[0-4]\\d|25[0-5])$"; private static final Pattern m_pattern = Pattern.compile(IPADDRESS_PATTERN); /** * Validate ip address with regular expression * @param ip ip address for validation * @return true valid ip address, false invalid ip address */ private boolean validate(final String ip) { final Matcher matcher = m_pattern.matcher(ip); return matcher.matches(); } }