/*
* 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.internal.ccb;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.onecmdb.core.ICCBListener;
import org.onecmdb.core.ICcb;
import org.onecmdb.core.ICi;
import org.onecmdb.core.ICmdbTransaction;
import org.onecmdb.core.IObjectScope;
import org.onecmdb.core.IRFC;
import org.onecmdb.core.IRfcResult;
import org.onecmdb.core.ISession;
import org.onecmdb.core.ITicket;
import org.onecmdb.core.internal.ccb.workers.RfcResult;
import org.onecmdb.core.internal.model.ItemId;
import org.onecmdb.core.internal.model.QueryResult;
import org.onecmdb.core.internal.storage.IDaoReader;
import org.onecmdb.core.internal.storage.IDaoWriter;
import org.onecmdb.core.utils.xml.BeanCache;
import org.springframework.context.MessageSource;
public class OneCmdbCcb implements ICcb {
private IDaoWriter writer;
private IDaoReader reader;
private List<IRfcWorker> rfcWorkers;
private MessageSource messageSource;
private ICmdbTransaction bootUp;
private boolean syncronicMode = true;
private ISession session;
private List<ICCBListener> ccbListeners = new ArrayList<ICCBListener>();
private Log log = null;
public ISession getSession() {
return session;
}
public void setSession(ISession session) {
this.session = session;
}
public void setRfcWorkers(List<IRfcWorker> workers) {
this.rfcWorkers = workers;
}
public void setMessageSource(MessageSource messageSource) {
this.messageSource = messageSource;
}
public void setSyncronic(boolean value) {
this.syncronicMode = value;
}
public void setDaoReader(IDaoReader reader) {
this.reader = reader;
}
public void setDaoWriter(IDaoWriter writer) {
this.writer = writer;
}
public void setStartupTransaction(ICmdbTransaction boot) {
this.bootUp = boot;
}
public void addChangeListener(ICCBListener listener) {
if (ccbListeners.contains(listener)) {
return;
}
ccbListeners.add(listener);
}
public boolean removeChangeListener(ICCBListener listener) {
boolean exists = ccbListeners.remove(listener);
return(exists);
}
public void init() {
getLogger().info("OneCMDB CCB startup.");
ICmdbTransaction trans = reader.getTransaction(bootUp.getId());
if (trans == null) {
getLogger().info("Start boot up sequence");
debug(dumpTransaction(bootUp));
getSession().login();
if (bootUp instanceof CmdbTransaction) {
((CmdbTransaction)bootUp).setSession(getSession());
}
rfc(bootUp);
getSession().logout();
// writer.storeTransaction(bootUp);
// processTransaction(bootUp);
} else {
// Already Started.
getLogger().info("Boot up sequence already performed.");
}
getLogger().info("OneCMDB CCB startup completeted.");
}
public ICmdbTransaction getTx(ISession session) {
// TODO: Validate credentials.
CmdbTransaction tx = new CmdbTransaction();
// Only here we can set the Issue's session.
tx.setSession(session);
return (tx);
}
public ITicket submitTx(ICmdbTransaction tx) {
ITicket ticket = this.rfc(tx);
return (ticket);
}
/**
* Persite the transaction/ and all it's rfc's.
*/
private ITicket rfc(ICmdbTransaction tx) {
// debug(dumpTransaction(tx));
//updateTxId(tx, tx.getRfcs());
if (syncronicMode) {
tx.setInsertTs(new Date());
tx.setStatus(ICmdbTransaction.REGISTERED_STATE);
// For now same thread thread
processTransaction(tx);
} else {
tx.setInsertTs(new Date());
tx.setStatus(ICmdbTransaction.REGISTERED_STATE);
writer.storeTransaction(tx);
}
return (new CmdbTransactionTicket(tx.getId()));
}
private IRfcWorker getRfcWorker(IRFC rfc) {
if (this.rfcWorkers == null) {
return (null);
}
for (IRfcWorker worker : this.rfcWorkers) {
if (worker.handleRfc(rfc)) {
return (worker);
}
}
return (null);
}
/*
private void updateTxId(ICmdbTransaction tx, List<IRFC> rfcs) {
for (IRFC rfc : rfcs) {
// System.out.println("SET TX[" + tx.getId()+ " to RFC[" +
// rfc.toString() + "]");
rfc.setTxId(tx.getId().asLong());
updateTxId(tx, rfc.getRfcs());
}
}
*/
private void processTransaction(ICmdbTransaction tr) {
tr.setBeginTs(new Date());
log.info("PROCESS TX START - " + tr);
IObjectScope scope = new CcbObjectScope(tr.getSession(), this.reader);
try {
IRfcResult result = processRfcs(tr, tr.getRfcs(), scope);
if (result.isRejected()) {
tr.setStatus(ICmdbTransaction.REJECTED_STATE);
tr.setRejectCause(result.getRejectCause());
} else {
tr.setStatus(ICmdbTransaction.COMMITED_STATE);
}
} catch (Throwable t) {
log.error("CMDB TX Internal Error:", t);
t.printStackTrace();
tr.setStatus(ICmdbTransaction.REJECTED_STATE);
tr.setRejectCause("Internal Error: " + t.toString());
} finally {
tr.setEndTs(new Date());
if (tr.getStatus() == ICmdbTransaction.REJECTED_STATE) {
log.info("PROCESS RFC REJECTED - " + tr);;
writer.rejectTransaction(tr);
} else {
log.info("PROCESS RFC DONE - " + tr);;
tr.setCiModified(scope.getCiModified());
tr.setCiAdded(scope.getCiAdded());
tr.setCiDeleted(scope.getCiDeleted());
writer.commitTransaction(scope, tr);
fireChangeEvent(scope);
// TODO: handle this through notification.
// Easier to do this by a static call!
BeanCache.getInstance().invalidate(scope);
}
log.info("PROCESS TX END - " + tr);;
}
}
private void fireChangeEvent(IObjectScope scope) {
for (ICCBListener listener: ccbListeners) {
listener.onChange(scope);
}
}
private IRfcResult processRfcs(ICmdbTransaction tx, List<IRFC> rfcs,
IObjectScope scope) {
for (IRFC rfc : rfcs) {
// Check if set, could be a potential problem
// to modify ts, but the tx will hold
// excatly when this rfc was performed and
// that can not be set by the client.
if (rfc.getTs() == null) {
rfc.setTs(new Date());
}
rfc.setTxId(tx.getId().asLong());
IRfcWorker worker = getRfcWorker(rfc);
/*
System.out.println("PROCESS RFC[" + rfc + "] --> WORKER[" + worker
+ "]");
*/
if (worker == null) {
RfcResult result = new RfcResult();
result.setRejectCause("ERROR CODE: No worker found for rfc["
+ rfc.getClass().getSimpleName() + "]");
/*
* String message = messageSource.getMessage(
* "org.onecmdb.ccb.error.norfcworker", new Object[]
* {rfc.getClass().getName()}, "No RFC Worker found for class
* {0}", Locale.getDefault() )
*/
return (result);
}
IRfcResult result = worker.perform(rfc, scope);
if (result.isRejected()) {
log.warn("\tREJECTED : RFC[" + rfc + "] : "
+ result.getRejectCause());
return (result);
}
log.debug("\tPROCESSED RFC[" + rfc + "] TXID["
+ rfc.getTxId() + "]");
// An RFC can generet new RFC's, need to update TXid.
if (rfc.getRfcs().size() > 0) {
//updateTxId(tx, rfc.getRfcs());
result = processRfcs(tx, rfc.getRfcs(), scope);
if (result.isRejected()) {
return (result);
}
}
}
return (new RfcResult());
}
private void debug(String msg) {
getLogger().debug(msg);
}
private String dumpTransaction(ICmdbTransaction tx) {
StringBuffer buffer = new StringBuffer();
buffer.append("TX[" + tx.getId() + "]");
buffer.append(" name=" + tx.getName());
buffer.append("\n");
buffer.append(" status=" + tx.getStatus());
buffer.append("\n");
buffer.append(" issuer=" + tx.getIssuer());
buffer.append("\n");
buffer.append(" inserted=" + tx.getInsertTs());
buffer.append("\n");
buffer.append(" begined=" + tx.getBeginTs());
buffer.append("\n");
buffer.append(" ended=" + tx.getEndTs());
buffer.append("\n");
buffer.append("---- RFCS[" + tx.getRfcs().size() + "]----");
buffer.append("\n");
buffer.append(dumpRfcs(tx.getRfcs(), " "));
buffer.append("---- RFCS ----");
buffer.append("\n");
return (buffer.toString());
}
private String dumpRfcs(List<IRFC> rfcs, String pad) {
StringBuffer buffer = new StringBuffer();
for (IRFC rfc : rfcs) {
buffer.append(pad);
buffer.append(rfc.toString() + "\n");
if (rfc.getRfcs().size() > 0) {
buffer.append(dumpRfcs(rfc.getRfcs(), pad + " "));
}
}
return (buffer.toString());
}
public ICi getRoot() {
// TODO Auto-generated method stub
return null;
}
private long DEFAULT_TIMEOUT = 60000;
public IRfcResult waitForTx(ITicket ticket) {
if (ticket instanceof CmdbTransactionTicket) {
long startTime = System.currentTimeMillis();
while (true) {
ICmdbTransaction tx = reader
.getTransaction(((CmdbTransactionTicket) ticket)
.getTxId());
if (tx == null) {
throw new IllegalStateException("Transaction ticket["
+ ticket.toString() + "] is not registered!");
}
RfcResult result = new RfcResult();
result.setTxId(tx.getId().asLong());
result.setIssuer(tx.getIssuer());
result.setStart(tx.getBeginTs());
result.setStop(tx.getEndTs());
result.setCiDeleted(tx.getCiDeleted());
result.setCiAdded(tx.getCiAdded());
result.setCiModified(tx.getCiModified());
if (tx.getStatus() == ICmdbTransaction.COMMITED_STATE) {
return (result);
}
if (tx.getStatus() == ICmdbTransaction.REJECTED_STATE) {
result.setRejectCause(tx.getRejectCause());
return (result);
}
// TODO: How to handle exceptions....
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
throw new IllegalArgumentException(
"INTERUPPTED: The wait fro transaction has been interrupted");
}
if ((System.currentTimeMillis() - startTime) > DEFAULT_TIMEOUT) {
throw new IllegalArgumentException(
"TIMEOUT: The transaction has not been proceesed yet");
}
}
}
throw new IllegalArgumentException("Not a correct transaction ticket["
+ ticket.toString() + "]");
}
public void close() {
getLogger().info("Closing OneCMDB...");
for (IRfcWorker wrk : this.rfcWorkers) {
}
getLogger().info("OneCMDB has now been closed.");
}
private Log getLogger() {
if (this.log == null) {
this.log = LogFactory.getLog(this.getClass());
}
return(this.log);
}
public List<IRFC> findRFCForCi(ICi ci) {
List<IRFC> list = reader.findRFCForCi(ci.getId());
return (list);
}
public ICmdbTransaction findTxForRfc(IRFC rfc) {
ICmdbTransaction tx = reader.getTransaction(new ItemId(rfc.getTxId()));
return (tx);
}
public List<IRFC> queryRFCForCi(ICi ci, RfcQueryCriteria crit) {
QueryResult<IRFC> rfcs = reader.queryRfc(ci, crit, false);
return(rfcs);
}
public int queryRFCForCiCount(ICi ci, RfcQueryCriteria crit) {
QueryResult<IRFC> rfcs = reader.queryRfc(ci, crit, true);
return(rfcs.getTotalHits());
}
public void addChangeListsner(ICCBListener listener) {
// TODO Auto-generated method stub
}
}