/*
* codjo.net
*
* Common Apache License 2.0
*/
package net.codjo.control.common;
import java.sql.Connection;
import java.sql.SQLException;
import java.sql.Statement;
import java.sql.Timestamp;
import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import net.codjo.control.common.util.EntityIterator;
import net.codjo.control.common.util.EntityResultState;
import org.apache.log4j.Logger;
/**
* Classe representant un plan d'int�gration.
*
* @author $Author: gonnot $
* @version $Revision: 1.11 $
*/
public class IntegrationPlan {
private static final Logger APP = Logger.getLogger(IntegrationPlan.class);
private static final ControlContext DEFAULT_CONTEXT =
new ControlContext("auto", "auto", null);
public static final String CLEANUP_TYPE_DELETE = "delete";
public static final String CLEANUP_TYPE_DROP = "drop";
private Dictionary dictionary = new Dictionary();
private String controlTableDef;
private String description;
private Plan dispatch;
private String id;
private PlansList planList;
private PlansList planListForDelete;
private Shipment shipment;
private Entity entity;
private StepsList abstractSteps = new StepsList();
private String cleanUpType = CLEANUP_TYPE_DROP;
public IntegrationPlan() {
}
public void setControlTableDef(String controlTableDef) {
this.controlTableDef = controlTableDef;
}
public void setDescription(String description) {
this.description = description;
}
public void setDictionary(Dictionary dictionary) {
this.dictionary = dictionary;
}
public void setDispatch(Plan dispatch) {
this.dispatch = dispatch;
}
public void setEntity(Entity entity) {
this.entity = entity;
}
public void setId(String id) {
this.id = id;
}
public void setPlanList(PlansList planList) {
this.planList = planList;
}
public void setPlanListForDelete(PlansList planListForDelete) {
this.planListForDelete = planListForDelete;
}
public void setShipment(net.codjo.control.common.Shipment shipment) {
this.shipment = shipment;
}
public String getControlTableDef() {
return controlTableDef;
}
public String getDescription() {
return description;
}
public Dictionary getDictionary() {
return dictionary;
}
public Plan getDispatch() {
return dispatch;
}
public Entity getEntity() {
return entity;
}
public String getId() {
return id;
}
public PlansList getPlanList() {
return planList;
}
public PlansList getPlanListForDelete() {
return planListForDelete;
}
public StepsList getAbstractSteps() {
return abstractSteps;
}
public void setAbstractSteps(StepsList abstractSteps) {
this.abstractSteps.addStepsList(abstractSteps);
}
public String getQuarantineTable() {
if (getShipment() != null && getShipment().getFrom() != null) {
return getDictionary().replaceVariables(getShipment().getFrom());
}
else {
return null;
}
}
public Step getStep(String stepId) {
for (Plan plan : getPlanList().getPlans()) {
for (Step step : plan.getSteps()) {
if (step.getId().equals(stepId)) {
return step;
}
}
}
throw new IllegalArgumentException("Step " + stepId + " is unknown");
}
public net.codjo.control.common.Shipment getShipment() {
return shipment;
}
public void cleanUp(final Connection con) throws SQLException {
if (CLEANUP_TYPE_DELETE.equals(cleanUpType)) {
deleteControlTable(con);
}
else if (CLEANUP_TYPE_DROP.equals(cleanUpType)) {
dropControlTable(con);
}
else {
throw new IllegalArgumentException("cleanup type unknown (delete or drop).");
}
}
/**
* DEPRECATED.
*
* @param con con
*
* @throws SQLException SQLException
* @throws ControlException si un contr�le �choue
* @deprecated utiliser la version avec contexte.
*/
@Deprecated
public void executeBatchControls(final Connection con)
throws SQLException, ControlException {
executeBatchControls(con, DEFAULT_CONTEXT);
}
public void executeBatchControls(final Connection con, final ControlContext context)
throws SQLException, ControlException {
APP.debug("-------- Lancement des controles " + getId());
ImmutableControlContext immutableCtxt = new ImmutableControlContext(context);
for (Plan plan : getPlanList().getPlans()) {
if (plan.isJavaMode()) {
EntityIterator iter =
getEntity().getEntityHelperForBatch().iterator(con, getControlTableName());
try {
controlRows(plan, immutableCtxt, iter);
}
finally {
iter.close();
}
}
else {
String pathOfRequest = "batch";
if (context != null) {
pathOfRequest = context.getPathOfRequest();
}
Map<Step, StepAudit> stepAudit = new HashMap<Step, StepAudit>();
plan.executeMASS(con, getDictionary(), immutableCtxt, pathOfRequest,
getControlTableName(), stepAudit);
printStepAudit(stepAudit, pathOfRequest, Plan.MASS_TYPE);
}
}
}
public void executeDispatch(final Connection con, final ControlContext context)
throws SQLException, ControlException {
APP.debug("-------- Lancement du dispatch " + getId());
ImmutableControlContext immutableCtxt = new ImmutableControlContext(context);
Map<Step, StepAudit> stepAudit = new HashMap<Step, StepAudit>();
getDispatch().executeMASS(con, getDictionary(), immutableCtxt, Step.FOR_ALL,
getControlTableName(), stepAudit);
printStepAudit(stepAudit, Step.FOR_ALL, Plan.MASS_TYPE);
}
public void executeShipmemt(final Connection con)
throws SQLException {
long start = 0;
if (APP.isDebugEnabled()) {
start = System.currentTimeMillis();
APP.debug("-------- Lancement du Shipment " + getId());
}
getShipment().execute(con, getDictionary());
if (APP.isDebugEnabled()) {
long end = System.currentTimeMillis();
APP.debug("-------- Fin du Shipment " + getId() + " en "
+ ((end - start) / 1000) + " s");
}
}
public void init(final Connection con) throws SQLException {
getDictionary().setNow(new Timestamp(System.currentTimeMillis()));
createControlTable(con);
}
/**
* DEPRECATED.
*
* @param con la connection
* @param vo Objet a controler
*
* @throws SQLException Erreur SQL
* @throws ControlException Control en erreur
* @deprecated utiliser la version avec contexte.
*/
@Deprecated
public void proceedDeletedEntity(Connection con, Object vo)
throws SQLException, ControlException {
proceedDeletedEntity(con, vo, DEFAULT_CONTEXT);
}
public void proceedDeletedEntity(Connection con, Object vo, final ControlContext ctxt)
throws SQLException, ControlException {
if (getPlanListForDelete() == null) {
return;
}
ctxt.setConnection(con);
proceedEntity(Step.FOR_USER, con, vo, new ImmutableControlContext(ctxt),
getPlanListForDelete());
}
/**
* @deprecated utilis� la version {@link #proceedUpdatedEntity(java.sql.Connection, Object, ControlContext)}
*/
@Deprecated
public void proceedEntity(final Connection con, final Object vo,
final ControlContext ctxt) throws SQLException, ControlException {
proceedUpdatedEntity(con, vo, ctxt);
}
public void proceedUpdatedEntity(final Connection con, final Object vo,
final ControlContext ctxt) throws SQLException, ControlException {
APP.debug("-------- Lancement des controles pour une modification " + getId());
ctxt.setConnection(con);
proceedEntity(Step.FOR_USER_UPDATE, con, vo, new ImmutableControlContext(ctxt),
getPlanList());
}
/**
* DEPRECATED.
*
* @param con la connection
* @param vo Objet a controler
*
* @throws SQLException Erreur SQL
* @throws ControlException Control en erreur
* @deprecated utiliser la version avec contexte.
*/
@Deprecated
public void proceedNewEntity(Connection con, Object vo)
throws SQLException, ControlException {
proceedNewEntity(con, vo, DEFAULT_CONTEXT);
}
public void proceedNewEntity(final Connection con, final Object vo,
final ControlContext ctxt) throws SQLException, ControlException {
APP.debug("-------- Lancement des controles pour un ajout " + getId());
ctxt.setConnection(con);
proceedEntity(Step.FOR_USER_ADD, con, vo, new ImmutableControlContext(ctxt),
getPlanList());
}
/**
* DEPRECATED.
*
* @param con la connection
*
* @throws SQLException Erreur SQL
* @throws ControlException Erreur dans MassControl
* @deprecated utiliser la version avec contexte.
*/
@Deprecated
public void proceedQuarantine(Connection con)
throws SQLException, ControlException {
proceedQuarantine(con, DEFAULT_CONTEXT);
}
public void proceedQuarantine(final Connection con, final ControlContext context)
throws SQLException, ControlException {
APP.debug("---------------------- Integration " + getId());
context.setConnection(con);
init(con);
try {
executeShipmemt(con);
executeBatchControls(con, context);
executeDispatch(con, context);
}
finally {
dropControlTable(con);
}
}
protected void createControlTable(Connection con)
throws SQLException {
if (getControlTableDef() == null) {
return;
}
// Desactive le drop pour eviter d'avoir des traces d'erreur dans weblo
// du style: table '#tmp' ne peut etre drop
// dropControlTable(con);
Statement stmt = con.createStatement();
try {
stmt.executeUpdate(getDictionary().replaceVariables(getControlTableDef()));
if (stmt.getWarnings() != null) {
throw stmt.getWarnings();
}
}
finally {
stmt.close();
}
}
public String getControlTableName() {
return getDictionary().replaceVariables(getShipment().getTo());
}
private void controlRows(final Plan plan, final ImmutableControlContext context,
final EntityIterator iter) {
Map<Step, StepAudit> stepAudit = new HashMap<Step, StepAudit>();
while (iter.hasNext()) {
Object item = iter.next();
try {
plan.executeJAVA(item, getDictionary(), context, Step.FOR_BATCH, stepAudit);
iter.update(item, null);
}
catch (ControlException ex) {
iter.update(item, ex);
}
}
printStepAudit(stepAudit, Step.FOR_BATCH, Plan.JAVA_TYPE);
}
private void printStepAudit(Map<Step, StepAudit> stepAuditMap, String pathOfRequest, String stepType) {
Set<Entry<Step, StepAudit>> entries = stepAuditMap.entrySet();
for (Entry<Step, StepAudit> entry : entries) {
Step step = entry.getKey();
StepAudit stepAudit = entry.getValue();
if (stepAudit.getOkRunningCount() > 0) {
APP.info("For " + stepType + " step " + step.getId() + " match stepFor:" + step.getStepFor()
+ ", receive:"
+ pathOfRequest + " --> " + "step called " +
stepAudit.getOkRunningCount() + " time(s) in "
+ stepAudit.getOkRunningDuration() + ".");
}
else {
APP.info("For " + stepType + " step " + step.getId() + " match stepFor:" + step.getStepFor()
+ ", receive:"
+ pathOfRequest + " --> " + "step skipped " +
stepAudit.getNotOkRunningCount() + " time(s).");
}
}
}
private void dropControlTable(Connection con) throws SQLException {
if (getControlTableDef() == null) {
return;
}
Statement stmt = con.createStatement();
try {
stmt.executeUpdate("drop table " + getControlTableName());
}
catch (SQLException e) {
APP.debug("Drop de la table " + getControlTableName(), e);
}
finally {
stmt.close();
}
}
private void deleteControlTable(Connection con) throws SQLException {
Statement stmt = con.createStatement();
try {
stmt.executeUpdate("delete from " + getControlTableName());
}
catch (SQLException e) {
APP.debug("Delete de la table " + getControlTableName(), e);
}
finally {
stmt.close();
}
}
private void proceedEntity(String stepType, Connection con, Object vo,
final ImmutableControlContext context, PlansList plansToProceed)
throws SQLException, ControlException {
init(con);
try {
boolean firstSql = true;
for (Plan plan : plansToProceed.getPlans()) {
if (plan.hasStepFor(stepType)) {
if (plan.isJavaMode()) {
Map<Step, StepAudit> stepAudit = new HashMap<Step, StepAudit>();
plan.executeJAVA(vo, getDictionary(), context, stepType, stepAudit);
printStepAudit(stepAudit, stepType, Plan.JAVA_TYPE);
}
else {
String tableName = getControlTableName();
if (firstSql) {
getEntity().getEntityHelper().insertIntoTable(con, vo, tableName);
firstSql = false;
}
else {
getEntity().getEntityHelper().updateTable(con, vo, tableName);
}
Map<Step, StepAudit> stepAudit = new HashMap<Step, StepAudit>();
plan.executeMASS(con, getDictionary(), context, stepType, getControlTableName(),
stepAudit);
printStepAudit(stepAudit, stepType, Plan.MASS_TYPE);
EntityResultState entityState =
getEntity().getEntityHelper().updateObject(con, vo, tableName);
throwIfError(entityState);
}
}
}
}
finally {
cleanUp(con);
}
}
private void throwIfError(EntityResultState entityState)
throws ControlException {
if (entityState.getErrorType() != EntityResultState.NO_ERROR) {
throw new ControlException(entityState);
}
}
public void setCleanUpType(String cleanUpType) {
this.cleanUpType = cleanUpType;
}
public String getCleanUpType() {
return cleanUpType;
}
}