Java handler example
Example code explores the capabilities of Java™ handlers.
package com.foo.initiate.hub.link;
import java.util.Map;
import java.util.HashMap;
import madison.handler.CallbackHandlerException;
import madison.handler.HandlerExtBase;
import madison.handler.IService;
import madison.mpi.MemHead;
import madison.mpi.MemRowList;
import madison.mpi.RowIterator;
import madison.mpi.EntIque;
import madison.mpi.Row;
import madison.mpi.EntXeia;
import madison.mpi.UsrHead;
import madison.mpi.IxnMemPut;
import madison.mpi.RowInd;
import madison.mpi.PutType;
import madison.mpi.MemMode;
import madison.mpi.MatchMode;
import madison.mpi.Context;
import madison.util.ClassTest;
/**
* A Java callout handler for BML testing.
*/
public class HandlerBML extends HandlerExtBase {
private static final String TEST_NAME =
"TestLTEIDChangeCallout";
private static final String ENT_TYPE = "LT_BML";
private static final int EIATYPE_AUTOLINKSS = 1;
private static final int EIATYPE_AUTOLINKMS = 2;
private static final int EIATYPE_REPROCESS = 14;
/**
* An enumeration to track move types.
*/
private static enum MoveType {
/**
* Moving from the trusted source entity and
* then back.
*/
NoChange,
/**
* Moving from the trusted source to a new entity
* on reprocess.
*/
EntityMove,
/**
* Moving from the trusted source to a singleton
* only.
*/
NewEntity,
/**
* New members moving into an entity on reprocess.
*/
NewMember
}
@Override
protected void entMng(IService service) throws
CallbackHandlerException {
info("entMng [" + getName() + "]");
if (!service.getEntType().equals(ENT_TYPE)) {
// not our desired entity type so bail quick
return;
}
// we're looking for reprocessed members from
// the TestLTEIDChangeCallout test
MemRowList inputRows = service.getInpMemRowList();
MemHead memhead = null; // we need the memhead
that got updated
EntIque entique = null; // we need the entique
row to know it's reprocess
RowIterator rowIterator = inputRows.rows();
// loop over the rows until we find the two we're
looking for or there aren't any more
while (rowIterator.hasMoreRows() && (memhead ==
null || entique == null)) {
Row row = rowIterator.nextRow();
if (row instanceof MemHead) {
memhead = (MemHead) row;
} else if (row instanceof EntIque) {
entique = (EntIque) row;
}
}
// if we didn't find the two rows we're looking for
// we're done
if (memhead == null || entique == null) {
warn("Could not find memhead or entique row.");
return;
}
// we're only looking for Reprocess callouts
if (!entique.getWrkCode().equals("R")) {
return;
}
String memIdnum = memhead.getMemIdnum();
// we're only looking for member updates from
// our test
if (!memIdnum.startsWith(TEST_NAME)) {
return;
}
// examine the EIA rows to determine any moves
Map<Long, MoveType> moves = mapMemberMoves(inpu
tRows);
// get the memRecno from the entique so we can
// check the member we're testing
long memRecno = entique.getMemRecno();
MoveType moveType = moves.get(memRecno);
// memIdnum indicates which test we're working on
if (memIdnum.equals(TEST_NAME + "A1")) {
if (moveType == MoveType.NoChange) {
putMember(service.getContext(), "F1");
} else {
error("Expect unit test failure due to invalid
moveType.");
}
} else if (memIdnum.equals(TEST_NAME + "A2")) {
if (moveType == MoveType.EntityMove) {
putMember(service.getContext(), "F1");
} else {
error("Expect unit test failure due to invalid
moveType.");
}
} else if (memIdnum.equals(TEST_NAME + "A3")) {
if (moveType == MoveType.NewEntity) {
putMember(service.getContext(), "F1");
} else {
error("Expect unit test failure due to invalid
moveType.");
}
} else if (memIdnum.equals(TEST_NAME + "A4")) {
if (moveType == MoveType.NoChange) {
putMember(service.getContext(), "F1");
} else {
error("Expect unit test failure due to invalid
moveType.");
}
} else if (memIdnum.equals(TEST_NAME + "A5")) {
if (moveType == MoveType.EntityMove) {
putMember(service.getContext(), "F1");
} else {
error("Expect unit test failure due to invalid
moveType.");
}
} else if (memIdnum.equals(TEST_NAME + "A6")) {
if (moveType == MoveType.NewEntity) {
putMember(service.getContext(), "F1");
} else {
error("Expect unit test failure due to invalid
moveType.");
}
}
}
/**
* A method for determining if an EID change happened
* for a given member during a Best Match Linking entity
* update. When a trusted source member is udpated,
* all of the related members are forced into singleton
* entities and reprocessed by the entity manager. This
* method examines the entity manager callout data to
* determine what type of entity move occurred when
* the non-trusted source members were reprocessed.
* <p/>
* This method should be passed the input rows provided
* to the callout when the EntIque row's wrkCode has an
* "R" (reprocess) value. This code is NOT the same
* value present in the service arguments in the callout.
* Using this method in the callout on non-reprocessed
* members will result in invalid results.
*
* @param inputRows a MemRowList provided by the
* entity manager callout that
* contains EntXeia rows for a
* specific audrecno.
* @return a mapping of memRecno to MoveType for
* all members present in the
* inputRows parameter.
*/
protected Map<Long, MoveType> mapMemberMoves(MemRo
wList inputRows) {
if (isDebugEnabled()) {
debug("Mapping member moves");
}
// we need to map the entxeia rows
Map<String, EntXeia> eiaMap = new HashMap<String,En
tXeia>();
RowIterator rowIterator = inputRows.rows(new Cla
ssTest(new EntXeia()));
long memRecno;
int eiaTypeno;
while (rowIterator.hasMoreRows()) {
EntXeia row = (EntXeia) rowIterator.nextRow();
// map has a compound key of memRecno-eiatype
memRecno = row.getMemRecno();
eiaTypeno = row.getEiaTypeno();
if (isDebugEnabled()) {
debug("Mapping entxeia row " + memRecno + "-" +
eiaTypeno);
}
eiaMap.put(memRecno + "-" + eiaTypeno, row);
}
// track movements
Map<Long, MoveType> moves = new HashMap<Long, MoveT
ype>();
MoveType moveType;
// walk the map to determine the move types
for (String key : eiaMap.keySet()) {
String[] keyParts = key.split("-");
memRecno = Long.valueOf(keyParts[0]);
eiaTypeno = Integer.valueOf(keyParts[1]);
moveType = moves.get(memRecno);
if (eiaTypeno == EIATYPE_AUTOLINKSS || eiaTypeno
== EIATYPE_AUTOLINKMS)
{
// if eiaTypeno in {1,2} AutoLink
// we should have a corresponding eiaTypeno 14
if (eiaMap.containsKey(memRecno + "-" + EIATY
PE_REPROCESS)) {
// we can figure out the entity moves
long startEntRecno = eiaMap.get(memRecno +
"-" +
EIATYPE_REPROCESS).getPrevEntRecno();
long endEntRecno = eiaMap.get(key).getSupEntR
ecno();
if (startEntRecno == endEntRecno) {
moves.put(memRecno, MoveType.NoChange);
} else {
moves.put(memRecno, MoveType.EntityMove);
}
} else {
// a link without a reprocess is simply a new
// member joining this entity
moves.put(memRecno, MoveType.NewMember);
}
} else if (moveType == null && eiaTypeno == EIATYPE_R
EPROCESS) {
// if eiaTypeno == 14 TSUpdReprocess and we don't
// have a moveType then we can assume we're a
// singleton
moves.put(memRecno, MoveType.NewEntity);
}
}
if (isDebugEnabled()) {
debug("Move map: " + moves);
}
return moves;
}
/**
* Creates a member with the specified tinyIdnum.
*
* @param context used to create the member
* @param tinyIdnum the member's tiny ID number
* @throws CallbackHandlerException if the member
* can't be created
*/
protected void putMember(Context context, String tin
yIdnum) throws CallbackHandlerException {
if (isDebugEnabled()) {
debug("Creating member with tinyIdnum: " + tinyI
dnum);
}
// no user/pw available from entMng
UsrHead usrHead = new UsrHead("system", "system");
IxnMemPut ixnMemPut = new IxnMemPut(context);
ixnMemPut.setEntType(ENT_TYPE);
MemRowList inpMemRows = new MemRowList();
MemRowList outMemRows = new MemRowList();
MemHead memHeadPut = new MemHead();
memHeadPut.setSrcCode(ENT_TYPE + "_" + tinyIdnum.ch
arAt(0));
memHeadPut.setMemIdnum(TEST_NAME + tinyIdnum);
memHeadPut.setRowInd(RowInd.INSERT);
inpMemRows.addRow(memHeadPut);
if (!ixnMemPut.execute(usrHead, inpMemRows, outMemRows,
PutType.INSERT_ONLY, MemMode.COMPLETE, MatchMode.D
ONOTHING))
{
throw new CallbackHandlerException("Unable to put Memb
er - " + ixnMemPut.getErrCode() + ": " + ixnMemPu
t.getErrText());
}
}
}