/*******************************************************************************
* 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.web.rest;
import java.text.ParseException;
import java.util.List;
import java.util.Set;
import java.util.TreeSet;
import javax.ws.rs.Consumes;
import javax.ws.rs.DELETE;
import javax.ws.rs.GET;
import javax.ws.rs.POST;
import javax.ws.rs.PUT;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.HttpHeaders;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.SecurityContext;
import javax.ws.rs.core.UriInfo;
import org.joda.time.Duration;
import org.opennms.netmgt.provision.persist.ForeignSourceRepository;
import org.opennms.netmgt.provision.persist.StringIntervalPropertyEditor;
import org.opennms.netmgt.provision.persist.foreignsource.DetectorCollection;
import org.opennms.netmgt.provision.persist.foreignsource.DetectorWrapper;
import org.opennms.netmgt.provision.persist.foreignsource.ForeignSource;
import org.opennms.netmgt.provision.persist.foreignsource.ForeignSourceCollection;
import org.opennms.netmgt.provision.persist.foreignsource.PluginConfig;
import org.opennms.netmgt.provision.persist.foreignsource.PolicyCollection;
import org.opennms.netmgt.provision.persist.foreignsource.PolicyWrapper;
import org.springframework.beans.BeanWrapper;
import org.springframework.beans.PropertyAccessorFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;
import com.sun.jersey.spi.resource.PerRequest;
/**
*<p>RESTful service to the OpenNMS Provisioning Foreign Source definitions. Foreign source
*definitions are used to control the scanning (service detection) of services for SLA monitoring
*as well as the data collection settings for physical interfaces (resources).</p>
*<p>This API supports CRUD operations for managing the Provisioner's foreign source definitions. Foreign
*source definitions are POSTed and will be deployed when the corresponding requisition (provisioning group)
*gets imported by provisiond.
*<ul>
*<li>GET/PUT/POST pending foreign sources</li>
*<li>GET pending and deployed count</li>
*</ul>
*</p>
*<p>Example 1: Create a new foreign source<i>Note: The foreign-source attribute typically has a 1 to 1
*relationship to a provisioning group (a.k.a. requisition). The relationship is only
*implied by name and it is a best practice to use the same name for all three. If a requisition exists with
*the same name as a foreign source, it will be used during the provisioning (import) operations in lieu
*of the default foreign source.</i></p>
*<pre>
*curl -X POST \
* -H "Content-Type: application/xml" \
* -d <?xml version="1.0" encoding="UTF-8" standalone="yes"?>
* <foreign-source date-stamp="2009-03-07T20:22:45.625-05:00" name="Cisco"
* xmlns:ns2="http://xmlns.opennms.org/xsd/config/model-import"
* xmlns="http://xmlns.opennms.org/xsd/config/foreign-source">
* <scan-interval>1d</scan-interval>
* <detectors>
* <detector class="org.opennms.netmgt.provision.detector.datagram.DnsDetector" name="DNS"/>
* <detector class="org.opennms.netmgt.provision.detector.simple.FtpDetector" name="FTP"/>
* <detector class="org.opennms.netmgt.provision.detector.simple.HttpDetector" name="HTTP"/>
* <detector class="org.opennms.netmgt.provision.detector.simple.HttpsDetector" name="HTTPS"/>
* <detector class="org.opennms.netmgt.provision.detector.icmp.IcmpDetector" name="ICMP"/>
* <detector class="org.opennms.netmgt.provision.detector.simple.LdapDetector" name="LDAP"/>
* <detector class="org.opennms.netmgt.provision.detector.snmp.SnmpDetector" name="SNMP"/>
* <detector class="org.opennms.netmgt.provision.detector.ssh.SshDetector" name="SSH"/>
* </detectors>
* <policies>
* <policy class="org.opennms.netmgt.provision.persist.policies.MatchingInterfacePolicy" name="policy1">
* <parameter value="~10\.*\.*\.*" key="ipAddress"/>
* </policy>
* </policies>
* </foreign-source> \
* -u admin:admin \
* http://localhost:8980/opennms/rest/foreignSources
*</pre>
*<p>Example 2: Query SNMP community string.</p>
*<pre>
*curl -X GET \
* -H "Content-Type: application/xml" \
* -u admin:admin \
* http://localhost:8980/opennms/rest/foreignSources/deployed \
* 2>/dev/null \
* |xmllint --format -</pre>
*
* @author <a href="mailto:ranger@opennms.org">Benjamin Reed</a>
* @version $Id: $
* @since 1.8.1
*/
@Component
@PerRequest
@Scope("prototype")
@Path("foreignSources")
public class ForeignSourceRestService extends OnmsRestService {
@Autowired
@Qualifier("pending")
private ForeignSourceRepository m_pendingForeignSourceRepository;
@Autowired
@Qualifier("deployed")
private ForeignSourceRepository m_deployedForeignSourceRepository;
@Context
UriInfo m_uriInfo;
@Context
HttpHeaders m_headers;
@Context
SecurityContext m_securityContext;
/**
* <p>getDefaultForeignSource</p>
*
* @return a {@link org.opennms.netmgt.provision.persist.foreignsource.ForeignSource} object.
* @throws java.text.ParseException if any.
*/
@GET
@Path("default")
@Produces( { MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
public ForeignSource getDefaultForeignSource() throws ParseException {
readLock();
try {
return m_deployedForeignSourceRepository.getDefaultForeignSource();
} finally {
readUnlock();
}
}
/**
* Returns all the deployed foreign sources
*
* @return Collection of OnmsForeignSources (ready to be XML-ified)
* @throws java.text.ParseException if any.
*/
@GET
@Path("deployed")
public ForeignSourceCollection getDeployedForeignSources() throws ParseException {
readLock();
try {
return new ForeignSourceCollection(m_deployedForeignSourceRepository.getForeignSources());
} finally {
readUnlock();
}
}
/**
* returns a plaintext string being the number of pending foreign sources
*
* @return a int.
*/
@GET
@Path("deployed/count")
@Produces(MediaType.TEXT_PLAIN)
public int getDeployedCount() {
readLock();
try {
return m_pendingForeignSourceRepository.getForeignSourceCount();
} finally {
readUnlock();
}
}
/**
* Returns the union of deployed and pending foreign sources
*
* @return Collection of OnmsForeignSources (ready to be XML-ified)
* @throws java.text.ParseException if any.
*/
@GET
@Produces( { MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
public ForeignSourceCollection getForeignSources() throws ParseException {
readLock();
try {
Set<ForeignSource> foreignSources = new TreeSet<ForeignSource>();
for (String fsName : getActiveForeignSourceNames()) {
foreignSources.add(getActiveForeignSource(fsName));
}
return new ForeignSourceCollection(foreignSources);
} finally {
readUnlock();
}
}
/**
* returns a plaintext string being the number of pending foreign sources
*
* @return a int.
* @throws java.text.ParseException if any.
*/
@GET
@Path("count")
@Produces(MediaType.TEXT_PLAIN)
public int getTotalCount() throws ParseException {
readLock();
try {
return getActiveForeignSourceNames().size();
} finally {
readUnlock();
}
}
/**
* Returns the requested {@link ForeignSource}
*
* @param foreignSource the foreign source name
* @return the foreign source
*/
@GET
@Path("{foreignSource}")
@Produces( { MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
public ForeignSource getForeignSource(@PathParam("foreignSource") String foreignSource) {
readLock();
try {
return getActiveForeignSource(foreignSource);
} finally {
readUnlock();
}
}
/**
* <p>getDetectors</p>
*
* @param foreignSource a {@link java.lang.String} object.
* @return a {@link org.opennms.netmgt.provision.persist.foreignsource.DetectorCollection} object.
*/
@GET
@Path("{foreignSource}/detectors")
@Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
public DetectorCollection getDetectors(@PathParam("foreignSource") String foreignSource) {
readLock();
try {
return new DetectorCollection(getActiveForeignSource(foreignSource).getDetectors());
} finally {
readUnlock();
}
}
/**
* <p>getDetector</p>
*
* @param foreignSource a {@link java.lang.String} object.
* @param detector a {@link java.lang.String} object.
* @return a {@link org.opennms.netmgt.provision.persist.foreignsource.DetectorWrapper} object.
*/
@GET
@Path("{foreignSource}/detectors/{detector}")
@Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
public DetectorWrapper getDetector(@PathParam("foreignSource") String foreignSource, @PathParam("detector") String detector) {
readLock();
try {
for (PluginConfig pc : getActiveForeignSource(foreignSource).getDetectors()) {
if (pc.getName().equals(detector)) {
return new DetectorWrapper(pc);
}
}
return null;
} finally {
readUnlock();
}
}
/**
* <p>getPolicies</p>
*
* @param foreignSource a {@link java.lang.String} object.
* @return a {@link org.opennms.netmgt.provision.persist.foreignsource.PolicyCollection} object.
*/
@GET
@Path("{foreignSource}/policies")
@Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
public PolicyCollection getPolicies(@PathParam("foreignSource") String foreignSource) {
readLock();
try {
return new PolicyCollection(getActiveForeignSource(foreignSource).getPolicies());
} finally {
readUnlock();
}
}
/**
* <p>getPolicy</p>
*
* @param foreignSource a {@link java.lang.String} object.
* @param policy a {@link java.lang.String} object.
* @return a {@link org.opennms.netmgt.provision.persist.foreignsource.PolicyWrapper} object.
*/
@GET
@Path("{foreignSource}/policies/{policy}")
@Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
public PolicyWrapper getPolicy(@PathParam("foreignSource") String foreignSource, @PathParam("policy") String policy) {
readLock();
try {
for (PluginConfig pc : getActiveForeignSource(foreignSource).getPolicies()) {
if (pc.getName().equals(policy)) {
return new PolicyWrapper(pc);
}
}
return null;
} finally {
readUnlock();
}
}
/**
* <p>addForeignSource</p>
*
* @param foreignSource a {@link org.opennms.netmgt.provision.persist.foreignsource.ForeignSource} object.
* @return a {@link javax.ws.rs.core.Response} object.
*/
@POST
@Consumes(MediaType.APPLICATION_XML)
@Transactional
public Response addForeignSource(ForeignSource foreignSource) {
writeLock();
try {
log().debug("addForeignSource: Adding foreignSource " + foreignSource.getName());
m_pendingForeignSourceRepository.save(foreignSource);
return Response.ok(foreignSource).build();
} finally {
writeUnlock();
}
}
/**
* <p>addDetector</p>
*
* @param foreignSource a {@link java.lang.String} object.
* @param detector a {@link org.opennms.netmgt.provision.persist.foreignsource.DetectorWrapper} object.
* @return a {@link javax.ws.rs.core.Response} object.
*/
@POST
@Path("{foreignSource}/detectors")
@Consumes(MediaType.APPLICATION_XML)
@Transactional
public Response addDetector(@PathParam("foreignSource") String foreignSource, DetectorWrapper detector) {
writeLock();
try {
log().debug("addDetector: Adding detector " + detector.getName());
ForeignSource fs = getActiveForeignSource(foreignSource);
fs.addDetector(detector);
m_pendingForeignSourceRepository.save(fs);
return Response.ok(detector).build();
} finally {
writeUnlock();
}
}
/**
* <p>addPolicy</p>
*
* @param foreignSource a {@link java.lang.String} object.
* @param policy a {@link org.opennms.netmgt.provision.persist.foreignsource.PolicyWrapper} object.
* @return a {@link javax.ws.rs.core.Response} object.
*/
@POST
@Path("{foreignSource}/policies")
@Consumes(MediaType.APPLICATION_XML)
@Transactional
public Response addPolicy(@PathParam("foreignSource") String foreignSource, PolicyWrapper policy) {
writeLock();
try {
log().debug("addPolicy: Adding policy " + policy.getName());
ForeignSource fs = getActiveForeignSource(foreignSource);
fs.addPolicy(policy);
m_pendingForeignSourceRepository.save(fs);
return Response.ok(policy).build();
} finally {
writeUnlock();
}
}
/**
* <p>updateForeignSource</p>
*
* @param foreignSource a {@link java.lang.String} object.
* @param params a {@link org.opennms.web.rest.MultivaluedMapImpl} object.
* @return a {@link javax.ws.rs.core.Response} object.
*/
@PUT
@Path("{foreignSource}")
@Consumes(MediaType.APPLICATION_FORM_URLENCODED)
@Transactional
public Response updateForeignSource(@PathParam("foreignSource") String foreignSource, MultivaluedMapImpl params) {
writeLock();
try {
ForeignSource fs = getActiveForeignSource(foreignSource);
log().debug("updateForeignSource: updating foreign source " + foreignSource);
BeanWrapper wrapper = PropertyAccessorFactory.forBeanPropertyAccess(fs);
wrapper.registerCustomEditor(Duration.class, new StringIntervalPropertyEditor());
for(String key : params.keySet()) {
if (wrapper.isWritableProperty(key)) {
Object value = null;
String stringValue = params.getFirst(key);
value = wrapper.convertIfNecessary(stringValue, (Class<?>)wrapper.getPropertyType(key));
wrapper.setPropertyValue(key, value);
}
}
log().debug("updateForeignSource: foreign source " + foreignSource + " updated");
m_pendingForeignSourceRepository.save(fs);
return Response.ok(fs).build();
} finally {
writeUnlock();
}
}
/**
* <p>deletePendingForeignSource</p>
*
* @param foreignSource a {@link java.lang.String} object.
* @return a {@link javax.ws.rs.core.Response} object.
*/
@DELETE
@Path("{foreignSource}")
@Transactional
public Response deletePendingForeignSource(@PathParam("foreignSource") String foreignSource) {
writeLock();
try {
ForeignSource fs = getForeignSource(foreignSource);
log().debug("deletePendingForeignSource: deleting foreign source " + foreignSource);
m_pendingForeignSourceRepository.delete(fs);
return Response.ok(fs).build();
} finally {
writeUnlock();
}
}
/**
* <p>deleteDeployedForeignSource</p>
*
* @param foreignSource a {@link java.lang.String} object.
* @return a {@link javax.ws.rs.core.Response} object.
*/
@DELETE
@Path("deployed/{foreignSource}")
@Transactional
public Response deleteDeployedForeignSource(@PathParam("foreignSource") String foreignSource) {
writeLock();
try {
ForeignSource fs = getForeignSource(foreignSource);
log().debug("deleteDeployedForeignSource: deleting foreign source " + foreignSource);
m_deployedForeignSourceRepository.delete(fs);
return Response.ok(fs).build();
} finally {
writeUnlock();
}
}
/**
* <p>deleteDetector</p>
*
* @param foreignSource a {@link java.lang.String} object.
* @param detector a {@link java.lang.String} object.
* @return a {@link javax.ws.rs.core.Response} object.
*/
@DELETE
@Path("{foreignSource}/detectors/{detector}")
@Transactional
public Response deleteDetector(@PathParam("foreignSource") String foreignSource, @PathParam("detector") String detector) {
writeLock();
try {
ForeignSource fs = getActiveForeignSource(foreignSource);
List<PluginConfig> detectors = fs.getDetectors();
PluginConfig removed = removeEntry(detectors, detector);
if (removed != null) {
fs.setDetectors(detectors);
m_pendingForeignSourceRepository.save(fs);
return Response.ok(removed).build();
}
return Response.notModified().build();
} finally {
writeUnlock();
}
}
/**
* <p>deletePolicy</p>
*
* @param foreignSource a {@link java.lang.String} object.
* @param policy a {@link java.lang.String} object.
* @return a {@link javax.ws.rs.core.Response} object.
*/
@DELETE
@Path("{foreignSource}/policies/{policy}")
@Transactional
public Response deletePolicy(@PathParam("foreignSource") String foreignSource, @PathParam("policy") String policy) {
writeLock();
try {
ForeignSource fs = getActiveForeignSource(foreignSource);
List<PluginConfig> policies = fs.getPolicies();
PluginConfig removed = removeEntry(policies, policy);
if (removed != null) {
fs.setPolicies(policies);
m_pendingForeignSourceRepository.save(fs);
return Response.ok(removed).build();
}
return Response.notModified().build();
} finally {
writeUnlock();
}
}
private PluginConfig removeEntry(List<PluginConfig> plugins, String name) {
PluginConfig removed = null;
java.util.Iterator<PluginConfig> i = plugins.iterator();
while (i.hasNext()) {
PluginConfig pc = i.next();
if (pc.getName().equals(name)) {
removed = pc;
i.remove();
break;
}
}
return removed;
}
private Set<String> getActiveForeignSourceNames() {
Set<String> fsNames = m_pendingForeignSourceRepository.getActiveForeignSourceNames();
fsNames.addAll(m_deployedForeignSourceRepository.getActiveForeignSourceNames());
return fsNames;
}
private ForeignSource getActiveForeignSource(String foreignSourceName) {
ForeignSource fs = m_pendingForeignSourceRepository.getForeignSource(foreignSourceName);
if (fs.isDefault()) {
return m_deployedForeignSourceRepository.getForeignSource(foreignSourceName);
}
return fs;
}
}