/*
* Lokomo OneCMDB - An Open Source Software for Configuration
* Management of Datacenter Resources
*
* Copyright (C) 2006 Lokomo Systems AB
*
* This program 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 2 of the License, or (at
* your option) any later version.
*
* This program 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 this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301 USA.
*
* Lokomo Systems AB can be contacted via e-mail: info@lokomo.com or via
* paper mail: Lokomo Systems AB, Sv�rdv�gen 27, SE-182 33
* Danderyd, Sweden.
*
*/
package org.onecmdb.core.tests.wsdl;
import java.awt.BorderLayout;
import java.io.PrintStream;
import java.net.MalformedURLException;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import junit.framework.Assert;
import org.codehaus.xfire.client.XFireProxyFactory;
import org.codehaus.xfire.service.Service;
import org.codehaus.xfire.service.binding.ObjectServiceFactory;
import org.onecmdb.core.IRfcResult;
import org.onecmdb.core.Version;
import org.onecmdb.core.example.MaxMinAvg;
import org.onecmdb.core.tests.AbstractOneCmdbTestCase;
import org.onecmdb.core.tests.OneCMDBTestConfig;
import org.onecmdb.core.tests.OneCMDBTestSuiteAllDB;
import org.onecmdb.core.utils.bean.AttributeBean;
import org.onecmdb.core.utils.bean.CiBean;
import org.onecmdb.core.utils.wsdl.IOneCMDBWebService;
import org.onecmdb.core.utils.wsdl.OneCMDBWebServiceImpl;
public class TestWSDLPerformance extends AbstractOneCmdbTestCase {
public class ProducerControl {
private String name;
private String derivedAlias;
private String token;
private Report report;
private int totalCreateSize;
private int batchCreateSize;
private IOneCMDBWebService cmdbService;
public int getBatchCreateSize() {
return batchCreateSize;
}
public void setBatchCreateSize(int batchCreateSize) {
this.batchCreateSize = batchCreateSize;
}
public IOneCMDBWebService getCmdbService() {
return cmdbService;
}
public void setCmdbService(IOneCMDBWebService cmdbService) {
this.cmdbService = cmdbService;
}
public String getDerivedAlias() {
return derivedAlias;
}
public void setDerivedAlias(String derivedAlias) {
this.derivedAlias = derivedAlias;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Report getReport() {
return report;
}
public void setReport(Report report) {
this.report = report;
}
public String getToken() {
return token;
}
public void setToken(String token) {
this.token = token;
}
public int getTotalCreateSize() {
return totalCreateSize;
}
public void setTotalCreateSize(int totalCreateSize) {
this.totalCreateSize = totalCreateSize;
}
}
public class Report {
private MaxMinAvg created = new MaxMinAvg();
private MaxMinAvg failed = new MaxMinAvg();
private int totalFailed = 0;
private int totalCreated = 0;
private long start;
private String title;
private int totalCount;
public Report() {
this.start = System.currentTimeMillis();
}
public void addPost(IRfcResult result, int count, long dt) {
if (result.isRejected()) {
synchronized(failed) {
failed.addValue(dt);
totalFailed += count;
}
} else {
synchronized(created) {
created.addValue((double)dt/(double)count);
totalCreated += count;
}
}
}
public void setTitle(String title) {
this.title = title;
}
public String getResult() {
StringBuffer buffer = new StringBuffer();
buffer.append("===========================================================");
buffer.append("\n");
buffer.append("Title: " + this.title);
buffer.append("\n");
buffer.append("Core Version: " + Version.VERSION_STRING);
buffer.append("\n");
buffer.append("Date: " + new Date());
buffer.append("\n");
buffer.append("Total time:" + (System.currentTimeMillis() - this.start) + "ms");
buffer.append("\n");
buffer.append("Added: " + totalCreated + " in " + created.getAvg() + "[ms/ci] min=" + created.getMin() + "[ms/ci] max=" + created.getMax() + "[ms/ci]");
buffer.append("\n");
buffer.append("Failed: " + totalFailed + " in " + failed.getAvg() + "ms/ci total=" + failed.getTotal() + "ms");
buffer.append("\n");
buffer.append("===========================================================");
buffer.append("\n");
return(buffer.toString());
}
public String progress() {
return(totalCreated + "[" + totalCount + "] - " + created.getAvg() + "ms/ci");
}
public void setTotalCount(int i) {
this.totalCount = i;
}
}
public class MyThreadGroup {
private List<Thread> threads = new ArrayList<Thread>();
public void addThread(Thread t) {
threads.add(t);
}
/**
* Start all threads.
*
*/
public void start() {
for (Thread t: threads) {
t.start();
}
}
/**
* Join all threads.
*/
public void join() {
for (Thread t: threads) {
try {
t.join();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
public class Producer implements Runnable {
private ProducerControl ctrl;
public Producer(ProducerControl ctrl) {
this.ctrl = ctrl;
}
public void run() {
for (int i = 0; i < ctrl.getTotalCreateSize(); i++) {
List<CiBean> beans = new ArrayList<CiBean>();
for (int j = 0; j < ctrl.getBatchCreateSize(); j++) {
CiBean bean = new CiBean();
bean.setAlias(ctrl.getName() + "-" + i + "." + j);
bean.setDerivedFrom(ctrl.getDerivedAlias());
beans.add(bean);
}
long start = System.currentTimeMillis();
IRfcResult result = ctrl.getCmdbService().update(ctrl.getToken(), beans.toArray(new CiBean[0]), null);
long stop = System.currentTimeMillis();
ctrl.getReport().addPost(result, beans.size(), (stop-start));
}
}
}
public class Consumer implements Runnable {
public void run() {
}
}
private static final int CONCURRENT_THREADS = 10;
private static final int CREATE_COUNT = 50;
private static final int BATCH_CREATE_COUNT = 10;
private IOneCMDBWebService cmdbService;
private String token;
private boolean isRunning = true;
private Report report;
private boolean useRemote = false;
private String remoteURL = null;
public TestWSDLPerformance() {
super();
}
public TestWSDLPerformance(OneCMDBTestConfig config) {
super(config);
}
public void setRemoteURL(String url) {
if (url == null) {
useRemote = false;
remoteURL = url;
} else {
useRemote = true;
remoteURL = url;
}
}
public void setUp() {
if (useRemote) {
Service serviceModel = new ObjectServiceFactory().create(IOneCMDBWebService.class);
try {
cmdbService = (IOneCMDBWebService)(new XFireProxyFactory().create(serviceModel, remoteURL));
} catch (MalformedURLException e) {
e.printStackTrace();
fail("Can't connect to remote WebService ");
}
} else {
super.setUp();
// Create IWebService interface.
// Directly without going through the XFire!
OneCMDBWebServiceImpl impl = new OneCMDBWebServiceImpl();
impl.setOneCmdb(getCmdbContext());
cmdbService = impl;
}
// Authenticate.
try {
token = cmdbService.auth("admin", "123");
} catch (Exception e) {
fail("Login: " + e);
}
this.report = new Report();
this.report.setTitle(getConfig().getPerformanceReportTitle());
}
public void testWriteConcurrency() {
String templateAlias = "ConcurrentTest";
// Create typical base CI.
CiBean template = new CiBean();
template.setDerivedFrom("Ci");
template.setAlias(templateAlias);
template.setTemplate(true);
// Add 10 simple attributes.
for (int i = 0; i < 10; i++) {
AttributeBean a = new AttributeBean();
a.setAlias("a" + i);
a.setType("xs:string");
template.addAttribute(a);
}
IRfcResult result = cmdbService.update(token, new CiBean[] {template}, null);
Assert.assertEquals(null, result.getRejectCause());
// Start a progressmeter.
new Thread(new ProgressReporter(this)).start();
// Create 10 Writers, will create 100 each 10 at a time.
MyThreadGroup tg = new MyThreadGroup();
report.setTotalCount(CONCURRENT_THREADS * BATCH_CREATE_COUNT * CREATE_COUNT);
for (int i = 0; i < CONCURRENT_THREADS; i++) {
ProducerControl pCtrl = new ProducerControl();
pCtrl.setCmdbService(cmdbService);
pCtrl.setToken(token);
pCtrl.setBatchCreateSize(BATCH_CREATE_COUNT);
pCtrl.setTotalCreateSize(CREATE_COUNT);
pCtrl.setReport(report);
pCtrl.setDerivedAlias(templateAlias);
pCtrl.setName("Instance-Test-" + i);
tg.addThread(new Thread(new Producer(pCtrl)));
}
tg.start();
tg.join();
setFinished();
PrintStream ps = getConfig().getReportPrinter();
if (ps != null) {
ps.print(report.getResult());
}
}
public void setFinished() {
this.isRunning = false;
}
public static void main(String argv[]) {
JFrame frame = new JFrame();
final JTextArea area = new JTextArea();
frame.getContentPane().add(new JScrollPane(area), BorderLayout.CENTER);
frame.setSize(500, 500);
final TestWSDLPerformance test = new TestWSDLPerformance();
// Start a test thread.
new Thread(new Runnable() {
public void run() {
// Test SQLServer 2005.
test.setRemoteURL("http://192.168.1.15:8080/webservice/OneCMDB");
test.setUp();
test.getReport().setTitle("Using Remote Backend");
test.testWriteConcurrency();
area.append(test.getReport().getResult());
test.tearDown();
test.setRemoteURL(null);
// Test SQLServer 2005.
test.setDatasourceResource(OneCMDBTestConfig.SQLSERVER2005_CREATE_DROP_DATASOURCE);
test.setUp();
test.getReport().setTitle("Using SQLServer 2005 Backend");
test.testWriteConcurrency();
area.append(test.getReport().getResult());
test.tearDown();
// Test with Oracle.
// Start with HSQLDB
test.setDatasourceResource(OneCMDBTestConfig.ORACLE_10_SERVER_CREATE_DROP_DATASOURCE);
test.setUp();
test.getReport().setTitle("Using Oracle 10gExpress Backend");
test.testWriteConcurrency();
area.append(test.getReport().getResult());
test.tearDown();
// Start with HSQLDB
test.setDatasourceResource(OneCMDBTestConfig.HSQL_SERVER_CREATE_DROP_DATASOURCE);
test.setUp();
test.getReport().setTitle("Using HSQL-DB Backend");
test.testWriteConcurrency();
area.append(test.getReport().getResult());
test.tearDown();
// Run with MYSQL
test.setDatasourceResource(OneCMDBTestConfig.MYSQL_CREATE_DROP_DATASOURCE);
test.setUp();
test.getReport().setTitle("Using MySQL Backend");
test.testWriteConcurrency();
area.append(test.getReport().getResult());
test.tearDown();
test.setFinished();
}
}).start();
// Start a report thread.
new Thread(new Runnable() {
public void run() {
while (test.isRunning()) {
Report r = test.getReport();
if (r != null) {
area.append(r.progress());
area.append("\n");
}
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}).start();
frame.setVisible(true);
}
public Report getReport() {
return(this.report);
}
public boolean isRunning() {
return(this.isRunning);
}
class ProgressReporter implements Runnable {
private TestWSDLPerformance test;
public ProgressReporter(TestWSDLPerformance test) {
this.test = test;
}
public void run() {
while (test.isRunning()) {
Report r = test.getReport();
if (r != null) {
PrintStream ps = this.test.getConfig().getReportPrinter();
ps.println(r.progress());
}
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
}