/*******************************************************************************
* This file is part of OpenNMS(R).
*
* Copyright (C) 2006-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.web.svclayer.support;
import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.Map;
import java.util.Set;
import java.util.SortedSet;
import java.util.TreeSet;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;
import org.apache.commons.beanutils.MethodUtils;
import org.opennms.core.utils.PropertyPath;
import org.opennms.netmgt.EventConstants;
import org.opennms.netmgt.config.CapsdConfig;
import org.opennms.netmgt.dao.CategoryDao;
import org.opennms.netmgt.dao.NodeDao;
import org.opennms.netmgt.dao.ServiceTypeDao;
import org.opennms.netmgt.model.OnmsAssetRecord;
import org.opennms.netmgt.model.OnmsCategory;
import org.opennms.netmgt.model.OnmsServiceType;
import org.opennms.netmgt.model.PrimaryType;
import org.opennms.netmgt.model.events.EventBuilder;
import org.opennms.netmgt.model.events.EventProxy;
import org.opennms.netmgt.model.events.EventProxyException;
import org.opennms.netmgt.provision.persist.ForeignSourceRepository;
import org.opennms.netmgt.provision.persist.foreignsource.ForeignSource;
import org.opennms.netmgt.provision.persist.requisition.Requisition;
import org.opennms.netmgt.provision.persist.requisition.RequisitionAsset;
import org.opennms.netmgt.provision.persist.requisition.RequisitionCategory;
import org.opennms.netmgt.provision.persist.requisition.RequisitionInterface;
import org.opennms.netmgt.provision.persist.requisition.RequisitionMonitoredService;
import org.opennms.netmgt.provision.persist.requisition.RequisitionNode;
import org.opennms.web.api.Util;
import org.opennms.web.svclayer.ManualProvisioningService;
import org.springframework.dao.DataAccessResourceFailureException;
import org.springframework.util.Assert;
/**
* <p>DefaultManualProvisioningService class.</p>
*
* @author <a href="mailto:brozow@opennms.org">Mathew Brozowski</a>
* @author <a href="mailto:dj@opennms.org">DJ Gregor</a>
*/
public class DefaultManualProvisioningService implements ManualProvisioningService {
private ForeignSourceRepository m_deployedForeignSourceRepository;
private ForeignSourceRepository m_pendingForeignSourceRepository;
private NodeDao m_nodeDao;
private CategoryDao m_categoryDao;
private ServiceTypeDao m_serviceTypeDao;
private CapsdConfig m_capsdConfig;
private final ReadWriteLock m_globalLock = new ReentrantReadWriteLock();
private final Lock m_readLock = m_globalLock.readLock();
private final Lock m_writeLock = m_globalLock.writeLock();
/**
* <p>Constructor for DefaultManualProvisioningService.</p>
*/
public DefaultManualProvisioningService() {
}
/**
* <p>setDeployedForeignSourceRepository</p>
*
* @param repository a {@link org.opennms.netmgt.provision.persist.ForeignSourceRepository} object.
*/
public void setDeployedForeignSourceRepository(final ForeignSourceRepository repository) {
m_writeLock.lock();
try {
m_deployedForeignSourceRepository = repository;
} finally {
m_writeLock.unlock();
}
}
/**
* <p>setPendingForeignSourceRepository</p>
*
* @param repository a {@link org.opennms.netmgt.provision.persist.ForeignSourceRepository} object.
*/
public void setPendingForeignSourceRepository(final ForeignSourceRepository repository) {
m_writeLock.lock();
try {
m_pendingForeignSourceRepository = repository;
} finally {
m_writeLock.unlock();
}
}
/**
* <p>setNodeDao</p>
*
* @param nodeDao a {@link org.opennms.netmgt.dao.NodeDao} object.
*/
public void setNodeDao(final NodeDao nodeDao) {
m_writeLock.lock();
try {
m_nodeDao = nodeDao;
} finally {
m_writeLock.unlock();
}
}
/**
* <p>setCategoryDao</p>
*
* @param categoryDao a {@link org.opennms.netmgt.dao.CategoryDao} object.
*/
public void setCategoryDao(final CategoryDao categoryDao) {
m_writeLock.lock();
try {
m_categoryDao = categoryDao;
} finally {
m_writeLock.unlock();
}
}
/**
* <p>setServiceTypeDao</p>
*
* @param serviceTypeDao a {@link org.opennms.netmgt.dao.ServiceTypeDao} object.
*/
public void setServiceTypeDao(final ServiceTypeDao serviceTypeDao) {
m_serviceTypeDao = serviceTypeDao;
}
public void setCapsdConfig(final CapsdConfig capsdConfig) {
m_capsdConfig = capsdConfig;
}
/** {@inheritDoc} */
public Requisition addCategoryToNode(final String groupName, final String pathToNode, final String categoryName) {
m_writeLock.lock();
try {
final Requisition group = getProvisioningGroup(groupName);
final RequisitionNode node = PropertyUtils.getPathValue(group, pathToNode, RequisitionNode.class);
// final int catCount = node.getCategoryCount();
final RequisitionCategory category = new RequisitionCategory();
category.setName(categoryName);
node.putCategory(category);
// Assert.isTrue(node.getCategoryCount() == (catCount + 1), "Category was not added correctly");
m_pendingForeignSourceRepository.save(group);
return m_pendingForeignSourceRepository.getRequisition(groupName);
} finally {
m_writeLock.unlock();
}
}
/** {@inheritDoc} */
public Requisition addAssetFieldToNode(final String groupName, final String pathToNode, final String assetName, final String assetValue) {
m_writeLock.lock();
try {
final Requisition group = getProvisioningGroup(groupName);
final RequisitionNode node = PropertyUtils.getPathValue(group, pathToNode, RequisitionNode.class);
// final int assetCount = node.getAssetCount();
final RequisitionAsset asset = new RequisitionAsset();
asset.setName(assetName);
asset.setValue(assetValue);
node.putAsset(asset);
// Assert.isTrue(node.getCategoryCount() == (assetCount + 1), "Asset was not added correctly");
m_pendingForeignSourceRepository.save(group);
return m_pendingForeignSourceRepository.getRequisition(groupName);
} finally {
m_writeLock.unlock();
}
}
/** {@inheritDoc} */
public Requisition addInterfaceToNode(final String groupName, final String pathToNode, final String ipAddr) {
m_writeLock.lock();
try {
final Requisition group = getProvisioningGroup(groupName);
Assert.notNull(group, "Group should not be Null and is null groupName: " + groupName);
final RequisitionNode node = PropertyUtils.getPathValue(group, pathToNode, RequisitionNode.class);
Assert.notNull(node, "Node should not be Null and pathToNode: " + pathToNode);
PrimaryType snmpPrimary = PrimaryType.PRIMARY;
if (node.getInterfaceCount() > 0) {
snmpPrimary = PrimaryType.SECONDARY;
}
// final int ifaceCount = node.getInterfaceCount();
final RequisitionInterface iface = createInterface(ipAddr, snmpPrimary);
node.putInterface(iface);
// Assert.isTrue(node.getInterfaceCount() == (ifaceCount + 1), "Interface was not added correctly");
m_pendingForeignSourceRepository.save(group);
return m_pendingForeignSourceRepository.getRequisition(groupName);
} finally {
m_writeLock.unlock();
}
}
private RequisitionInterface createInterface(final String ipAddr, final PrimaryType snmpPrimary) {
final RequisitionInterface iface = new RequisitionInterface();
iface.setIpAddr(ipAddr);
iface.setStatus(1);
iface.setSnmpPrimary(snmpPrimary);
return iface;
}
/** {@inheritDoc} */
public Requisition addNewNodeToGroup(final String groupName, final String nodeLabel) {
m_writeLock.lock();
try {
final Requisition group = getProvisioningGroup(groupName);
final RequisitionNode node = createNode(nodeLabel, String.valueOf(System.currentTimeMillis()));
node.setBuilding(groupName);
group.insertNode(node);
m_pendingForeignSourceRepository.save(group);
return m_pendingForeignSourceRepository.getRequisition(groupName);
} finally {
m_writeLock.unlock();
}
}
private RequisitionNode createNode(final String nodeLabel, final String foreignId) {
final RequisitionNode node = new RequisitionNode();
node.setNodeLabel(nodeLabel);
node.setForeignId(foreignId);
return node;
}
/** {@inheritDoc} */
public Requisition addServiceToInterface(final String groupName, final String pathToInterface, final String serviceName) {
m_writeLock.lock();
try {
final Requisition group = getProvisioningGroup(groupName);
final RequisitionInterface iface = PropertyUtils.getPathValue(group, pathToInterface, RequisitionInterface.class);
final RequisitionMonitoredService monSvc = createService(serviceName);
iface.insertMonitoredService(monSvc);
m_pendingForeignSourceRepository.save(group);
return m_pendingForeignSourceRepository.getRequisition(groupName);
} finally {
m_writeLock.unlock();
}
}
/** {@inheritDoc} */
public Requisition getProvisioningGroup(final String name) {
m_readLock.lock();
try {
final Requisition deployed = m_deployedForeignSourceRepository.getRequisition(name);
final Requisition pending = m_pendingForeignSourceRepository.getRequisition(name);
return (pending == null)? deployed : pending;
} finally {
m_readLock.unlock();
}
}
/** {@inheritDoc} */
public Requisition saveProvisioningGroup(final String groupName, final Requisition group) {
m_writeLock.lock();
try {
group.setForeignSource(groupName);
m_pendingForeignSourceRepository.save(group);
return m_pendingForeignSourceRepository.getRequisition(groupName);
} finally {
m_writeLock.unlock();
}
}
/**
* <p>getProvisioningGroupNames</p>
*
* @return a {@link java.util.Collection} object.
*/
public Collection<String> getProvisioningGroupNames() {
m_readLock.lock();
try {
final Set<String> names = new TreeSet<String>();
for (final Requisition r : m_deployedForeignSourceRepository.getRequisitions()) {
names.add(r.getForeignSource());
}
for (final Requisition r : m_pendingForeignSourceRepository.getRequisitions()) {
names.add(r.getForeignSource());
}
return names;
} finally {
m_readLock.unlock();
}
}
/** {@inheritDoc} */
public Requisition createProvisioningGroup(final String name) {
m_writeLock.lock();
try {
final Requisition group = new Requisition();
group.setForeignSource(name);
m_pendingForeignSourceRepository.save(group);
return m_pendingForeignSourceRepository.getRequisition(name);
} finally {
m_writeLock.unlock();
}
}
private RequisitionMonitoredService createService(final String serviceName) {
final RequisitionMonitoredService svc = new RequisitionMonitoredService();
svc.setServiceName(serviceName);
return svc;
}
/** {@inheritDoc} */
public void importProvisioningGroup(final String groupName) {
m_writeLock.lock();
try {
// first we update the import timestamp
final Requisition group = getProvisioningGroup(groupName);
group.updateDateStamp();
saveProvisioningGroup(groupName, group);
// then we send an event to the importer
final EventProxy proxy = Util.createEventProxy();
final String url = m_pendingForeignSourceRepository.getRequisitionURL(groupName).toString();
Assert.notNull(url, "Could not find url for group "+groupName+". Does it exists?");
final EventBuilder bldr = new EventBuilder(EventConstants.RELOAD_IMPORT_UEI, "Web");
bldr.addParam(EventConstants.PARM_URL, url);
try {
proxy.send(bldr.getEvent());
} catch (final EventProxyException e) {
throw new DataAccessResourceFailureException("Unable to send event to import group "+groupName, e);
}
} finally {
m_writeLock.unlock();
}
}
/** {@inheritDoc} */
public Requisition deletePath(final String groupName, final String pathToDelete) {
m_writeLock.lock();
try {
final Requisition group = getProvisioningGroup(groupName);
final PropertyPath path = new PropertyPath(pathToDelete);
final Object objToDelete = path.getValue(group);
final Object parentObject = path.getParent() == null ? group : path.getParent().getValue(group);
final String propName = path.getPropertyName();
final String methodSuffix = Character.toUpperCase(propName.charAt(0))+propName.substring(1);
final String methodName = "delete"+methodSuffix;
try {
MethodUtils.invokeMethod(parentObject, methodName, new Object[] { objToDelete });
} catch (final NoSuchMethodException e) {
throw new IllegalArgumentException("Unable to find method "+methodName+" on object of type "+parentObject.getClass(), e);
} catch (final IllegalAccessException e) {
throw new IllegalArgumentException("unable to access property "+pathToDelete, e);
} catch (final InvocationTargetException e) {
throw new IllegalArgumentException("an execption occurred deleting "+pathToDelete, e);
}
m_pendingForeignSourceRepository.save(group);
return m_pendingForeignSourceRepository.getRequisition(groupName);
} finally {
m_writeLock.unlock();
}
}
/**
* <p>getAllGroups</p>
*
* @return a {@link java.util.Collection} object.
*/
public Collection<Requisition> getAllGroups() {
m_readLock.lock();
try {
final Collection<Requisition> groups = new LinkedList<Requisition>();
for(final String groupName : getProvisioningGroupNames()) {
groups.add(getProvisioningGroup(groupName));
}
return groups;
} finally {
m_readLock.unlock();
}
}
/** {@inheritDoc} */
public void deleteProvisioningGroup(final String groupName) {
m_writeLock.lock();
try {
final Requisition r = getProvisioningGroup(groupName);
if (r != null) {
m_pendingForeignSourceRepository.delete(r);
m_deployedForeignSourceRepository.delete(r);
}
} finally {
m_writeLock.unlock();
}
}
/** {@inheritDoc} */
public void deleteAllNodes(final String groupName) {
m_writeLock.lock();
try {
Requisition group = m_deployedForeignSourceRepository.getRequisition(groupName);
if (group != null) {
group.setNodes(new ArrayList<RequisitionNode>());
m_deployedForeignSourceRepository.save(group);
}
group = m_pendingForeignSourceRepository.getRequisition(groupName);
if (group != null) {
group.setNodes(new ArrayList<RequisitionNode>());
m_pendingForeignSourceRepository.save(group);
}
} finally {
m_writeLock.unlock();
}
}
/**
* <p>getGroupDbNodeCounts</p>
*
* @return a java$util$Map object.
*/
public Map<String, Integer> getGroupDbNodeCounts() {
m_readLock.lock();
try {
final Map<String, Integer> counts = new HashMap<String, Integer>();
for(final String groupName : getProvisioningGroupNames()) {
counts.put(groupName, m_nodeDao.getNodeCountForForeignSource(groupName));
}
return counts;
} finally {
m_readLock.unlock();
}
}
/**
* <p>getNodeCategoryNames</p>
*
* @return a {@link java.util.Collection} object.
*/
public Collection<String> getNodeCategoryNames() {
m_readLock.lock();
try {
final Collection<String> names = new LinkedList<String>();
for (final OnmsCategory category : m_categoryDao.findAll()) {
names.add(category.getName());
}
return names;
} finally {
m_readLock.unlock();
}
}
/**
* <p>getServiceTypeNames</p>
*
* @return a {@link java.util.Collection} object.
*/
public Collection<String> getServiceTypeNames(String groupName) {
final SortedSet<String> serviceNames = new TreeSet<String>();
m_readLock.lock();
try {
final ForeignSource pendingForeignSource = m_pendingForeignSourceRepository.getForeignSource(groupName);
final ForeignSource deployedForeignSource = m_deployedForeignSourceRepository.getForeignSource(groupName);
serviceNames.addAll(deployedForeignSource.getDetectorNames());
serviceNames.addAll(pendingForeignSource.getDetectorNames());
for (final OnmsServiceType type : m_serviceTypeDao.findAll()) {
serviceNames.add(type.getName());
}
serviceNames.addAll(m_capsdConfig.getConfiguredProtocols());
return serviceNames;
} finally {
m_readLock.unlock();
}
}
/**
* <p>getAssetFieldNames</p>
*
* @return a {@link java.util.Collection} object.
*/
public Collection<String> getAssetFieldNames() {
m_readLock.lock();
try {
return PropertyUtils.getProperties(new OnmsAssetRecord());
} finally {
m_readLock.unlock();
}
}
}