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());
		}
	}
}