/*******************************************************************************
* 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.importer;
import java.io.IOException;
import java.util.List;
import java.util.Map;
import org.opennms.core.utils.ThreadCategory;
import org.opennms.netmgt.EventConstants;
import org.opennms.netmgt.daemon.SpringServiceDaemon;
import org.opennms.netmgt.eventd.EventIpcManager;
import org.opennms.netmgt.importer.operations.AbstractSaveOrUpdateOperation;
import org.opennms.netmgt.importer.operations.ImportOperation;
import org.opennms.netmgt.importer.operations.ImportOperationsManager;
import org.opennms.netmgt.importer.operations.ImportStatistics;
import org.opennms.netmgt.model.events.EventBuilder;
import org.opennms.netmgt.model.events.EventListener;
import org.opennms.netmgt.model.events.EventUtils;
import org.opennms.netmgt.xml.event.Event;
import org.springframework.beans.factory.DisposableBean;
import org.springframework.core.io.Resource;
import org.springframework.core.io.UrlResource;
/**
* <p>ImporterService class.</p>
*
* @author ranger
* @version $Id: $
*/
public class ImporterService extends BaseImporter implements SpringServiceDaemon, DisposableBean, EventListener {
/** Constant <code>NAME="ModelImporter"</code> */
public static final String NAME = "ModelImporter";
private volatile Resource m_importResource;
private volatile EventIpcManager m_eventManager;
private volatile ImporterStats m_stats;
/**
* <p>doImport</p>
*/
public void doImport() {
doImport(null);
}
/**
* Begins importing from resource specified in model-importer.properties file or
* in event parameter: url. Import Resources are managed with a "key" called
* "foreignSource" specified in the XML retreived by the resource and can be overridden
* as a parameter of an event.
* @param event
*/
private void doImport(Event event) {
Resource resource = null;
try {
m_stats = new ImporterStats();
resource = ((event != null && getEventUrl(event) != null) ? new UrlResource(getEventUrl(event)) : m_importResource);
sendImportStarted(resource);
importModelFromResource(resource, m_stats, event);
log().info("Finished Importing: "+m_stats);
sendImportSuccessful(m_stats, resource);
} catch (IOException e) {
String msg = "IOException importing "+resource;
log().error(msg, e);
sendImportFailed(msg+": "+e.getMessage(), resource);
} catch (ModelImportException e) {
String msg = "Error parsing import data from "+resource;
log().error(msg, e);
sendImportFailed(msg+": "+e.getMessage(), resource);
}
}
private String getEventUrl(Event event) {
return EventUtils.getParm(event, EventConstants.PARM_URL);
}
/**
* <p>getStats</p>
*
* @return a {@link java.lang.String} object.
*/
public String getStats() { return (m_stats == null ? "No Stats Availabile" : m_stats.toString()); }
private void sendImportSuccessful(ImporterStats stats, Resource resource) {
EventBuilder builder = new EventBuilder(EventConstants.IMPORT_SUCCESSFUL_UEI, NAME);
builder.addParam(EventConstants.PARM_IMPORT_RESOURCE, resource.toString());
builder.addParam(EventConstants.PARM_IMPORT_STATS, stats.toString());
m_eventManager.sendNow(builder.getEvent());
}
private void sendImportFailed(String msg, Resource resource) {
EventBuilder builder = new EventBuilder(EventConstants.IMPORT_FAILED_UEI, NAME);
builder.addParam(EventConstants.PARM_IMPORT_RESOURCE, resource.toString());
builder.addParam(EventConstants.PARM_FAILURE_MESSAGE, msg);
m_eventManager.sendNow(builder.getEvent());
}
private void sendImportStarted(Resource resource) {
EventBuilder builder = new EventBuilder(EventConstants.IMPORT_STARTED_UEI, NAME);
builder.addParam(EventConstants.PARM_IMPORT_RESOURCE, resource.toString());
m_eventManager.sendNow(builder.getEvent());
}
/**
* <p>setImportResource</p>
*
* @param resource a {@link org.springframework.core.io.Resource} object.
*/
public void setImportResource(Resource resource) {
m_importResource = resource;
}
/**
* <p>getEventManager</p>
*
* @return a {@link org.opennms.netmgt.eventd.EventIpcManager} object.
*/
public EventIpcManager getEventManager() {
return m_eventManager;
}
/**
* <p>setEventManager</p>
*
* @param eventManager a {@link org.opennms.netmgt.eventd.EventIpcManager} object.
*/
public void setEventManager(EventIpcManager eventManager) {
m_eventManager = eventManager;
}
/** {@inheritDoc} */
protected ImportOperationsManager createImportOperationsManager(Map<String, Integer> assetNumbersToNodes, ImportStatistics stats) {
ImportOperationsManager opsMgr = super.createImportOperationsManager(assetNumbersToNodes, stats);
opsMgr.setEventMgr(m_eventManager);
return opsMgr;
}
/**
* <p>afterPropertiesSet</p>
*
* @throws java.lang.Exception if any.
*/
@Override
public void afterPropertiesSet() throws Exception {
m_eventManager.addEventListener(this, EventConstants.RELOAD_IMPORT_UEI);
}
/**
* <p>destroy</p>
*
* @throws java.lang.Exception if any.
*/
public void destroy() throws Exception {
m_eventManager.removeEventListener(this, EventConstants.RELOAD_IMPORT_UEI);
}
/**
* <p>getName</p>
*
* @return a {@link java.lang.String} object.
*/
public String getName() {
return NAME;
}
/** {@inheritDoc} */
public void onEvent(Event e) {
String oldPrefix = ThreadCategory.getPrefix();
try {
ThreadCategory.setPrefix(NAME);
if (!EventConstants.RELOAD_IMPORT_UEI.equals(e.getUei())) {
return;
}
doImport(e);
} finally {
ThreadCategory.setPrefix(oldPrefix);
}
}
public class ImporterStats implements ImportStatistics {
private Duration m_importDuration = new Duration("Importing");
private Duration m_auditDuration = new Duration("Auditing");
private Duration m_loadingDuration = new Duration("Loading");
private Duration m_processingDuration = new Duration("Processing");
private Duration m_preprocessingDuration = new Duration("Scanning");
private Duration m_relateDuration = new Duration("Relating");
private WorkEffort m_preprocessingEffort = new WorkEffort("Scan Effort");
private WorkEffort m_processingEffort = new WorkEffort("Write Effort");
private WorkEffort m_eventEffort = new WorkEffort("Event Sending Effort");
private int m_deleteCount;
private int m_insertCount;
private int m_updateCount;
private int m_eventCount;
public void beginProcessingOps() {
m_processingDuration.start();
}
public void finishProcessingOps() {
m_processingDuration.end();
}
public void beginPreprocessingOps() {
m_preprocessingDuration.start();
}
public void finishPreprocessingOps() {
m_preprocessingDuration.end();
}
public void beginPreprocessing(ImportOperation oper) {
if (oper instanceof AbstractSaveOrUpdateOperation) {
m_preprocessingEffort.begin();
}
}
public void finishPreprocessing(ImportOperation oper) {
if (oper instanceof AbstractSaveOrUpdateOperation) {
m_preprocessingEffort.end();
}
}
public void beginPersisting(ImportOperation oper) {
m_processingEffort.begin();
}
public void finishPersisting(ImportOperation oper) {
m_processingEffort.end();
}
public void beginSendingEvents(ImportOperation oper, List<Event> events) {
if (events != null) m_eventCount += events.size();
m_eventEffort.begin();
}
public void finishSendingEvents(ImportOperation oper, List<Event> events) {
m_eventEffort.end();
}
public void beginLoadingResource(Resource resource) {
m_loadingDuration.setName("Loading Resource: "+resource);
m_loadingDuration.start();
}
public void finishLoadingResource(Resource resource) {
m_loadingDuration.end();
}
public void beginImporting() {
m_importDuration.start();
}
public void finishImporting() {
m_importDuration.end();
}
public void beginAuditNodes() {
m_auditDuration.start();
}
public void finishAuditNodes() {
m_auditDuration.end();
}
public void setDeleteCount(int deleteCount) {
m_deleteCount = deleteCount;
}
public void setInsertCount(int insertCount) {
m_insertCount = insertCount;
}
public void setUpdateCount(int updateCount) {
m_updateCount = updateCount;
}
public void beginRelateNodes() {
m_relateDuration.start();
}
public void finishRelateNodes() {
m_relateDuration.end();
}
public String toString() {
StringBuffer stats = new StringBuffer();
stats.append("Deletes: ").append(m_deleteCount).append(' ');
stats.append("Updates: ").append(m_updateCount).append(' ');
stats.append("Inserts: ").append(m_insertCount).append('\n');
stats.append(m_importDuration).append(' ');
stats.append(m_loadingDuration).append(' ');
stats.append(m_auditDuration).append('\n');
stats.append(m_preprocessingDuration).append(' ');
stats.append(m_processingDuration).append(' ');
stats.append(m_relateDuration).append(' ');
stats.append(m_preprocessingEffort).append(' ');
stats.append(m_processingEffort).append(' ');
stats.append(m_eventEffort).append(' ');
if (m_eventCount > 0) {
stats.append("Avg ").append((double)m_eventEffort.getTotalTime()/(double)m_eventCount).append(" ms per event");
}
return stats.toString();
}
}
public class Duration {
private String m_name = null;
private long m_start = -1L;
private long m_end = -1L;
public Duration() {
this(null);
}
public Duration(String name) {
m_name = name;
}
public void setName(String name) {
m_name = name;
}
public void start() {
m_start = System.currentTimeMillis();
}
public void end() {
m_end = System.currentTimeMillis();
}
public long getLength() {
if (m_start == -1L) return 0L;
long end = (m_end == -1L ? System.currentTimeMillis() : m_end);
return end - m_start;
}
public String toString() {
return (m_name == null ? "" : m_name+": ")+(m_start == -1L ? "has not begun": elapsedTime());
}
private String elapsedTime() {
long duration = getLength();
long hours = duration / 3600000L;
duration = duration % 3600000L;
long mins = duration / 60000L;
duration = duration % 60000L;
long secs = duration / 1000L;
long millis = duration % 1000L;
StringBuffer elapsed = new StringBuffer();
if (hours > 0)
elapsed.append(hours).append("h ");
if (mins > 0)
elapsed.append(mins).append("m ");
if (secs > 0)
elapsed.append(secs).append("s ");
if (millis > 0)
elapsed.append(millis).append("ms");
return elapsed.toString();
}
}
public class WorkEffort {
private String m_name;
private long m_totalTime;
private long m_sectionCount;
private ThreadLocal<Duration> m_pendingSection = new ThreadLocal<Duration>();
public WorkEffort(String name) {
m_name = name;
}
public void begin() {
Duration pending = new Duration();
pending.start();
m_pendingSection.set(pending);
}
public void end() {
Duration pending = m_pendingSection.get();
m_sectionCount++;
m_totalTime += pending.getLength();
}
public long getTotalTime() {
return m_totalTime;
}
public String toString() {
StringBuffer buf = new StringBuffer();
buf.append("Total ").append(m_name).append(": ");
buf.append((double)m_totalTime/(double)1000L).append(" thread-seconds");
if (m_sectionCount > 0) {
buf.append(" Avg ").append(m_name).append(": ");
buf.append((double)m_totalTime/(double)m_sectionCount).append(" ms per node");
}
return buf.toString();
}
}
/**
* <p>start</p>
*
* @throws java.lang.Exception if any.
*/
public void start() throws Exception {
// nothing to do -- we're event-driven
}
}