/*******************************************************************************
* 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.netmgt.dao.hibernate;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.io.StringWriter;
import java.io.Writer;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.exolab.castor.xml.MarshalException;
import org.exolab.castor.xml.Marshaller;
import org.exolab.castor.xml.ValidationException;
import org.hibernate.HibernateException;
import org.hibernate.Session;
import org.opennms.core.xml.CastorUtils;
import org.opennms.core.xml.MarshallingResourceFailureException;
import org.opennms.netmgt.config.monitoringLocations.LocationDef;
import org.opennms.netmgt.config.monitoringLocations.Locations;
import org.opennms.netmgt.config.monitoringLocations.MonitoringLocationsConfiguration;
import org.opennms.netmgt.config.tags.Tag;
import org.opennms.netmgt.config.tags.Tags;
import org.opennms.netmgt.dao.LocationMonitorDao;
import org.opennms.netmgt.model.LocationMonitorIpInterface;
import org.opennms.netmgt.model.OnmsApplication;
import org.opennms.netmgt.model.OnmsIpInterface;
import org.opennms.netmgt.model.OnmsLocationMonitor;
import org.opennms.netmgt.model.OnmsLocationMonitor.MonitorStatus;
import org.opennms.netmgt.model.OnmsLocationSpecificStatus;
import org.opennms.netmgt.model.OnmsMonitoredService;
import org.opennms.netmgt.model.OnmsMonitoringLocationDefinition;
import org.springframework.core.io.Resource;
import org.springframework.orm.hibernate3.HibernateCallback;
/**
* <p>LocationMonitorDaoHibernate class.</p>
*
* @author <a href="mailto:david@opennms.org">David Hustace</a>
*/
public class LocationMonitorDaoHibernate extends AbstractDaoHibernate<OnmsLocationMonitor, Integer> implements
LocationMonitorDao {
private MonitoringLocationsConfiguration m_monitoringLocationsConfiguration;
private Resource m_monitoringLocationConfigResource;
private Map<String, LocationDef> m_locationDefs = new HashMap<String, LocationDef>();
/**
* Constructor that also initializes the required XML configurations
*
* @throws IOException if any.
* @throws MarshalException if any.
* @throws ValidationException if any.
*/
public LocationMonitorDaoHibernate() {
super(OnmsLocationMonitor.class);
}
/** {@inheritDoc} */
@Override
protected void initDao() throws Exception {
super.initDao();
assertPropertiesSet();
initializeConfigurations();
}
/**
* <p>findAllMonitoringLocationDefinitions</p>
*
* @return a {@link java.util.List} object.
*/
public List<OnmsMonitoringLocationDefinition> findAllMonitoringLocationDefinitions() {
final Locations locations = m_monitoringLocationsConfiguration.getLocations();
if (locations != null) {
final List<LocationDef> locationDefCollection = locations.getLocationDefCollection();
if (locationDefCollection != null) {
return convertDefs(locationDefCollection);
}
}
return new ArrayList<OnmsMonitoringLocationDefinition>();
}
private List<OnmsMonitoringLocationDefinition> convertDefs(final List<LocationDef> defs) {
final List<OnmsMonitoringLocationDefinition> onmsDefs = new LinkedList<OnmsMonitoringLocationDefinition>();
for (final LocationDef def : defs) {
onmsDefs.add(convertDef(def));
}
return onmsDefs;
}
private OnmsMonitoringLocationDefinition convertDef(final LocationDef def) {
final OnmsMonitoringLocationDefinition onmsDef = new OnmsMonitoringLocationDefinition();
onmsDef.setArea(def.getMonitoringArea());
onmsDef.setName(def.getLocationName());
onmsDef.setPollingPackageName(def.getPollingPackageName());
onmsDef.setGeolocation(def.getGeolocation());
onmsDef.setCoordinates(def.getCoordinates());
onmsDef.setPriority(def.getPriority());
if (def.getTags() != null) {
final Set<String> tags = new HashSet<String>();
for (final Tag t : def.getTags().getTagCollection()) {
tags.add(t.getName());
}
onmsDef.setTags(tags);
}
return onmsDef;
}
/**
* {@inheritDoc}
*
* Don't call this for now.
*/
public void saveMonitoringLocationDefinitions(final Collection<OnmsMonitoringLocationDefinition> onmsDefs) {
for (final OnmsMonitoringLocationDefinition onmsDef : onmsDefs) {
LocationDef def = findLocationDef(onmsDef.getName());
if (def != null) {
updateLocationDef(def, onmsDef);
}
}
saveMonitoringConfig();
}
private void updateLocationDef(final LocationDef def, final OnmsMonitoringLocationDefinition onmsDef) {
def.setMonitoringArea(onmsDef.getArea());
def.setPollingPackageName(onmsDef.getPollingPackageName());
def.setGeolocation(onmsDef.getGeolocation());
def.setCoordinates(onmsDef.getCoordinates());
def.setPriority(onmsDef.getPriority());
final Tags tags = new Tags();
for (final String tag : onmsDef.getTags()) {
final Tag t = new Tag();
t.setName(tag);
tags.addTag(t);
}
def.setTags(tags);
}
/** {@inheritDoc} */
public void saveMonitoringLocationDefinition(final OnmsMonitoringLocationDefinition onmsDef) {
LocationDef def = findLocationDef(onmsDef.getName());
if (def != null) {
updateLocationDef(def, onmsDef);
}
saveMonitoringConfig();
}
//TODO: figure out way to synchronize this
//TODO: write a castor template for the DAOs to use and do optimistic
// locking.
/**
* <p>saveMonitoringConfig</p>
*/
protected void saveMonitoringConfig() {
String xml = null;
final StringWriter writer = new StringWriter();
try {
Marshaller.marshal(m_monitoringLocationsConfiguration, writer);
xml = writer.toString();
saveXml(xml);
} catch (final MarshalException e) {
throw new MarshallingResourceFailureException("saveMonitoringConfig: couldn't marshal confg: \n"+
(xml != null ? xml : ""), e);
} catch (final ValidationException e) {
throw new MarshallingResourceFailureException("saveMonitoringConfig: couldn't validate confg: \n"+
(xml != null ? xml : ""), e);
} catch (final IOException e) {
throw new MarshallingResourceFailureException("saveMonitoringConfig: couldn't write confg: \n"+
(xml != null ? xml : ""), e);
}
}
/**
* <p>saveXml</p>
*
* @param xml a {@link java.lang.String} object.
* @throws java.io.IOException if any.
*/
protected void saveXml(final String xml) throws IOException {
if (xml != null) {
final Writer fileWriter = new OutputStreamWriter(new FileOutputStream(m_monitoringLocationConfigResource.getFile()), "UTF-8");
fileWriter.write(xml);
fileWriter.flush();
fileWriter.close();
}
}
/**
*
* @param definitionName
* @return
*/
private LocationDef findLocationDef(final String definitionName) {
return m_locationDefs.get(definitionName);
}
/**
* Initializes all required XML configuration files
* @throws MarshalException
* @throws ValidationException
* @throws IOException
*/
private void initializeConfigurations() {
initializeMonitoringLocationDefinition();
}
/**
* Initializes the monitoring locations configuration file
* @throws IOException
* @throws MarshalException
* @throws ValidationException
*/
private void initializeMonitoringLocationDefinition() {
m_monitoringLocationsConfiguration = CastorUtils.unmarshalWithTranslatedExceptions(MonitoringLocationsConfiguration.class, m_monitoringLocationConfigResource);
createLocationDefMap();
}
private void createLocationDefMap() {
if (m_monitoringLocationsConfiguration.getLocations() != null) {
for(LocationDef def : m_monitoringLocationsConfiguration.getLocations().getLocationDefCollection()) {
m_locationDefs.put(def.getLocationName(), def);
}
}
}
/**
* <p>findAllLocationDefinitions</p>
*
* @return a {@link java.util.Collection} object.
*/
public Collection<OnmsMonitoringLocationDefinition> findAllLocationDefinitions() {
final List<OnmsMonitoringLocationDefinition> eDefs = new LinkedList<OnmsMonitoringLocationDefinition>();
for (final LocationDef def : m_monitoringLocationsConfiguration.getLocations().getLocationDefCollection()) {
eDefs.add(convertDef(def));
}
return eDefs;
}
private void assertPropertiesSet() {
if (m_monitoringLocationConfigResource == null && m_monitoringLocationsConfiguration == null) {
throw new IllegalStateException("either "
+ "monitoringLocationConfigResource "
+ "or monitorLocationsConfiguration "
+ "must be set but is not");
}
}
/**
* <p>getMonitoringLocationConfigResource</p>
*
* @return a {@link org.springframework.core.io.Resource} object.
*/
public Resource getMonitoringLocationConfigResource() {
return m_monitoringLocationConfigResource;
}
/**
* <p>setMonitoringLocationConfigResource</p>
*
* @param monitoringLocationResource a {@link org.springframework.core.io.Resource} object.
*/
public void setMonitoringLocationConfigResource(final Resource monitoringLocationResource) {
m_monitoringLocationConfigResource = monitoringLocationResource;
initializeMonitoringLocationDefinition();
}
/** {@inheritDoc} */
public OnmsMonitoringLocationDefinition findMonitoringLocationDefinition(final String monitoringLocationDefinitionName) {
assertNotNull(monitoringLocationDefinitionName, "monitoringLocationDefinitionName must not be null");
final LocationDef locationDef = findLocationDef(monitoringLocationDefinitionName);
return locationDef == null ? null : convertDef(locationDef);
}
private void assertNotNull(final String monitoringLocationDefinitionName, String msg) {
if (monitoringLocationDefinitionName == null) {
throw new IllegalArgumentException(msg);
}
}
/** {@inheritDoc} */
public OnmsLocationSpecificStatus getMostRecentStatusChange(final OnmsLocationMonitor locationMonitor, final OnmsMonitoredService monSvc) {
final HibernateCallback<OnmsLocationSpecificStatus> callback = new HibernateCallback<OnmsLocationSpecificStatus>() {
public OnmsLocationSpecificStatus doInHibernate(final Session session) throws HibernateException, SQLException {
return (OnmsLocationSpecificStatus)session.createQuery("from OnmsLocationSpecificStatus status where status.locationMonitor = :locationMonitor and status.monitoredService = :monitoredService order by status.pollResult.timestamp desc")
.setEntity("locationMonitor", locationMonitor)
.setEntity("monitoredService", monSvc)
.setMaxResults(1)
.uniqueResult();
}
};
return getHibernateTemplate().execute(callback);
}
/** {@inheritDoc} */
public void saveStatusChange(final OnmsLocationSpecificStatus statusChange) {
getHibernateTemplate().save(statusChange);
}
/**
* {@inheritDoc}
*
* Returns the location monitors which have reported on services belonging to the provided application
*/
public Collection<OnmsLocationMonitor> findByApplication(final OnmsApplication application) {
return findObjects(OnmsLocationMonitor.class, "select distinct l from OnmsLocationSpecificStatus as status " +
"join status.monitoredService as m " +
"join m.applications a " +
"join status.locationMonitor as l " +
"where a = ? and status.id in ( " +
"select max(s.id) from OnmsLocationSpecificStatus as s " +
"group by s.locationMonitor, s.monitoredService " +
")", application);
// final Collection<OnmsLocationMonitor> monitors = new HashSet<OnmsLocationMonitor>();
// for (final OnmsLocationSpecificStatus status : getAllMostRecentStatusChanges()) {
// if (status.getMonitoredService().getApplications() != null
// && status.getMonitoredService().getApplications().contains(application)) {
// monitors.add(status.getLocationMonitor());
// }
// }
// return monitors;
}
/** {@inheritDoc} */
public Collection<OnmsLocationMonitor> findByLocationDefinition(final OnmsMonitoringLocationDefinition locationDefinition) {
return (Collection<OnmsLocationMonitor>)find("from OnmsLocationMonitor as mon where mon.definitionName = ?", locationDefinition.getName());
}
/**
* <p>getAllMostRecentStatusChanges</p>
*
* @return a {@link java.util.Collection} object.
*/
public Collection<OnmsLocationSpecificStatus> getAllMostRecentStatusChanges() {
return getAllStatusChangesAt(new Date());
}
/** {@inheritDoc} */
public Collection<OnmsLocationSpecificStatus> getAllStatusChangesAt(final Date timestamp) {
//select lm.*, lssc.* from location_specific_status_changes lssc join
//location_monitors lm on lm.id = lssc.locationmonitorid where lssc.id in
//(select max(id) from location_specific_status_changes group by locationmonitorid, ifserviceid) order by statustime;
return findObjects(OnmsLocationSpecificStatus.class,
"from OnmsLocationSpecificStatus as status " +
"left join fetch status.locationMonitor as l " +
"left join fetch status.monitoredService as m " +
"left join fetch m.serviceType " +
"left join fetch m.ipInterface " +
"where status.id in (" +
"select max(s.id) from OnmsLocationSpecificStatus as s " +
"where s.pollResult.timestamp <? " +
"group by s.locationMonitor, s.monitoredService " +
")",
timestamp);
// return findObjects(OnmsLocationSpecificStatus.class,
// "from OnmsLocationSpecificStatus as status " +
// "where status.pollResult.timestamp = ( " +
// " select max(recentStatus.pollResult.timestamp) " +
// " from OnmsLocationSpecificStatus as recentStatus " +
// " where recentStatus.pollResult.timestamp < ? " +
// " group by recentStatus.locationMonitor, recentStatus.monitoredService " +
// " having recentStatus.locationMonitor = status.locationMonitor " +
// " and recentStatus.monitoredService = status.monitoredService " +
// ")",
// timestamp);
}
/** {@inheritDoc} */
public Collection<OnmsLocationSpecificStatus> getStatusChangesBetween(final Date startDate, final Date endDate) {
return findObjects(OnmsLocationSpecificStatus.class,
"from OnmsLocationSpecificStatus as status " +
"where ? <= status.pollResult.timestamp and status.pollResult.timestamp < ?",
startDate, endDate
);
}
/** {@inheritDoc} */
public Collection<OnmsLocationSpecificStatus> getStatusChangesForLocationBetween(final Date startDate, final Date endDate, final String locationName) {
final Collection<OnmsLocationSpecificStatus> statuses = getMostRecentStatusChangesForDateAndLocation(startDate, locationName);
statuses.addAll(findObjects(OnmsLocationSpecificStatus.class,
/*
"from OnmsLocationSpecificStatus as status " +
"where " +
"( " +
" select max(recentStatus.pollResult.timestamp) " +
" from OnmsLocationSpecificStatus as recentStatus " +
" where recentStatus.pollResult.timestamp < ? " +
" group by recentStatus.locationMonitor, recentStatus.monitoredService " +
" having recentStatus.locationMonitor = status.locationMonitor " +
" and recentStatus.monitoredService = status.monitoredService " +
") <= status.pollResult.timestamp " +
"and status.pollResult.timestamp < ?" +
"and status.locationMonitor.definitionName = ?",
startDate, endDate, locationName);
*/
"from OnmsLocationSpecificStatus as status " +
"where ? <= status.pollResult.timestamp " +
"and status.pollResult.timestamp < ? " +
"and status.locationMonitor.definitionName = ?",
startDate, endDate, locationName
));
return statuses;
}
/** {@inheritDoc} */
public Collection<OnmsLocationSpecificStatus> getStatusChangesForApplicationBetween(final Date startDate, final Date endDate, final String applicationName) {
return findObjects(OnmsLocationSpecificStatus.class,
"from OnmsLocationSpecificStatus as status " +
"left join fetch status.monitoredService as m " +
"left join fetch m.applications as a " +
"left join fetch status.locationMonitor as lm " +
"where " +
"a.name = ? " +
"and " +
"( status.pollResult.timestamp between ? and ?" +
" or" +
" status.id in " +
" (" +
" select max(s.id) from OnmsLocationSpecificStatus as s " +
" where s.pollResult.timestamp < ? " +
" group by s.locationMonitor, s.monitoredService " +
" )" +
")",
applicationName, startDate, endDate, startDate);
}
public Collection<OnmsLocationSpecificStatus> getStatusChangesBetweenForApplications(final Date startDate, final Date endDate, final Collection<String> applicationNames) {
return getHibernateTemplate().execute(new HibernateCallback<List<OnmsLocationSpecificStatus>>() {
@SuppressWarnings("unchecked")
public List<OnmsLocationSpecificStatus> doInHibernate(Session session) throws HibernateException, SQLException {
return (List<OnmsLocationSpecificStatus>)session.createQuery(
"select distinct status from OnmsLocationSpecificStatus as status " +
"left join fetch status.monitoredService as m " +
"left join fetch m.serviceType " +
"left join fetch m.applications as a " +
"left join fetch status.locationMonitor as lm " +
"where " +
"a.name in (:applicationNames) " +
"and " +
"( status.pollResult.timestamp between :startDate and :endDate" +
" or" +
" status.id in " +
" (" +
" select max(s.id) from OnmsLocationSpecificStatus as s " +
" where s.pollResult.timestamp < :startDate " +
" group by s.locationMonitor, s.monitoredService " +
" )" +
") order by status.pollResult.timestamp")
.setParameterList("applicationNames", applicationNames)
.setParameter("startDate", startDate)
.setParameter("endDate", endDate)
.list();
}
});
}
/** {@inheritDoc} */
public Collection<OnmsLocationSpecificStatus> getMostRecentStatusChangesForLocation(final String locationName) {
return getMostRecentStatusChangesForDateAndLocation(new Date(), locationName);
}
private Collection<OnmsLocationSpecificStatus> getMostRecentStatusChangesForDateAndLocation(final Date date, final String locationName) {
return findObjects(OnmsLocationSpecificStatus.class,
"from OnmsLocationSpecificStatus as status " +
"left join fetch status.locationMonitor as l " +
"left join fetch status.monitoredService as m " +
"left join fetch m.serviceType " +
"left join fetch m.ipInterface " +
"where status.pollResult.timestamp = ( " +
" select max(recentStatus.pollResult.timestamp) " +
" from OnmsLocationSpecificStatus as recentStatus " +
" where recentStatus.pollResult.timestamp < ? " +
" group by recentStatus.locationMonitor, recentStatus.monitoredService " +
" having recentStatus.locationMonitor = status.locationMonitor " +
" and recentStatus.monitoredService = status.monitoredService " +
") and l.definitionName = ?",
date, locationName);
}
/** {@inheritDoc} */
public Collection<LocationMonitorIpInterface> findStatusChangesForNodeForUniqueMonitorAndInterface(final int nodeId) {
@SuppressWarnings("unchecked")
final List<Object[]> l = getHibernateTemplate().find(
"select distinct status.locationMonitor, status.monitoredService.ipInterface from OnmsLocationSpecificStatus as status " +
"where status.monitoredService.ipInterface.node.id = ?",
nodeId
);
final HashSet<LocationMonitorIpInterface> ret = new HashSet<LocationMonitorIpInterface>();
for (Object[] tuple : l) {
OnmsLocationMonitor mon = (OnmsLocationMonitor) tuple[0];
OnmsIpInterface ip = (OnmsIpInterface) tuple[1];
ret.add(new LocationMonitorIpInterface(mon, ip));
}
return ret;
}
/** {@inheritDoc} */
public void pauseAll() {
getHibernateTemplate().bulkUpdate("update OnmsLocationMonitor as mon set mon.status = ? where mon.status != ?", MonitorStatus.PAUSED, MonitorStatus.STOPPED);
}
/** {@inheritDoc} */
public void resumeAll() {
getHibernateTemplate().bulkUpdate("update OnmsLocationMonitor as mon set mon.status = ? where mon.status = ?", MonitorStatus.STARTED, MonitorStatus.PAUSED);
}
}