Java Code to Work With MillennialMedia, SMAATO and NexAge Web Advertising APIs

I wrote yesterday about [link id='434' text="my (mostly) negative experience working with these companies"], but some of you might give it a try and maybe your results will be much better or maybe things have actually improved lately. In any case, the code here should get you up to speed covering most of the dirty work of working with these companies' APIs.

I will post 4 classes here:

If you are using this code, please give an attribution when applicable with a link to this post.

AdGrabber


/**
 * Abstract class for ad unit grabbing. Inheriting subclasses will implement ad serving platform specific web service interfaces.
 *
 * Copyright: Creative Common Attribution http://creativecommons.org/licenses/by/3.0/
 */
public abstract class AdGrabber {

	protected HashTableExt _adFieldPropertyBag;

	public AdGrabber(HashTableExt adFieldPropertyBag) {
		if (adFieldPropertyBag == null) {
			_adFieldPropertyBag = new HashTableExt();
		} else {
			_adFieldPropertyBag = adFieldPropertyBag;
		}
	}

	/**
	 * Inheriting classes have to implement the grabbing and the parsing of the ad from the appropriate ad serving web service
	 *
	 * @return
	 * 			- an {@link Ad} object populated with the values parsed from the appropriate ad serving web service
	 */
	public Ad grabTheAd() {
		try {
			Document adResponseDoc = StreamUtils.parseRemoteXML(getRequestURL(_adFieldPropertyBag));
			return parseServerResponse(adResponseDoc);
		} catch (Exception e) {
			//Log error
		}
		return new EmptyAd();
	}

	protected abstract String getRequestURL(HashTableExt adFieldPropertyBag);

	protected Ad parseServerResponse(Document doc) {
		Ad ad = null;

		if (doc == null) {
			return ad; // basically = return null
		}

		try {
			if (gotProperAd(doc)) {
				if (shouldParseAsImageAd(doc)) {
					ad = parseImageAd(doc);
				} else {
					ad = parseTextAd(doc);
				}

				ad.setNetwork(StringUtils.getClassName(this));

			} else { // did NOT get a proper ad
				ad = new EmptyAd();
			}

		} catch (Throwable t) {
			//Log error
		}

		return ad;
	}

	protected abstract boolean gotProperAd(Document doc) throws Exception;

	protected abstract TextAd parseTextAd(Document doc) throws Exception;

	protected abstract ImageAd parseImageAd(Document doc) throws Exception;

	protected abstract boolean shouldParseAsImageAd(Document doc) throws Exception;

}

MillenialAdGrabber


/**
 * Ad grabber that interfaces with Quattro Wireless service
 *
 * Copyright: Creative Common Attribution http://creativecommons.org/licenses/by/3.0/
 */
public class MillenialAdGrabber extends AdGrabber {

	/* ------------------------------------------			PUBLISHING CONSTANTS			------------------------------------------*/

	private static final String APP_ID = "YOUR_APP_ID";

	/* ------------------------------------------											------------------------------------------*/

	public MillenialAdGrabber(HashTableExt adFieldPropertyBag) {
		super(adFieldPropertyBag);
	}

	/**
	 *
	 * @param adFieldPropertyBag
	 * @return
	 * 			- The URL to be sent to the advertising web service
	 */
	protected String getRequestURL(HashTableExt adFieldPropertyBag) {
		StringBuffer sb = new StringBuffer("http://ads.mp.mydas.mobi/getAd.php5?");

		sb.append("apid=" + APP_ID);

		sb.append("&auid=" + BBInfo.getUniqueDeviceHash());

		sb.append("&uip=" + URLTools.urlEncodeBBForum(BBInfo.getIP())); // device IP

		sb.append("&ua=" + URLTools.urlEncodeBBForum(BBInfo.getUserAgent())); // USER AGENT

		return sb.toString();
	}

	/* ------------------------------------------------				AD response PARSING			------------------------------------------------ */

	protected boolean gotProperAd(Document doc) throws Exception {
		NodeList nl = ((NodeList) doc.getElementsByTagName("ad"));
		if (nl != null) {
			return nl.getLength() > 0;
		} else {
			return false;
		}
	}

	protected boolean shouldParseAsImageAd(Document doc) throws Exception {
		if (BBInfo.isTallScreen() || _adFieldPropertyBag.get(AdAllocManager.FETCH_IMAGE_ADS) != null) {
			if (!StringUtils.isEmpty(XML.getTextFromNode(doc.getElementsByTagName("url").item(0)))) {
				return true;
			}
		}

		return false;
	}

	protected TextAd parseTextAd(Document doc) throws Exception {
		TextAd ad = new TextAd();
		parseCommonAdValues(ad, doc);

		//parse the TEXT of the banner
		ad.setText(XML.getTextFromNode(doc.getElementsByTagName("altText").item(0)));

		return ad;
	}

	protected ImageAd parseImageAd(Document doc) throws Exception {
		ImageAd ad = new ImageAd();
		parseCommonAdValues(ad, doc);

		//parse the IMAGE of the banner
		String imageURL = XML.getNodeTextCumulative(doc.getElementsByTagName("url"));
		EncodedImage bannerImage = EncodedImage.createEncodedImage(StreamUtils.readRemoteStream(imageURL).getBytes(), 0, -1);
		ad.setImage(bannerImage);

		return ad;
	}

	/**
	 * Parse common values from the responce like the:
	 *  - tracking pixels/beacons
	 *  - the click URL
	 *
	 * @param ad
	 * @param doc
	 */
	private void parseCommonAdValues(Ad ad, Document doc) throws Exception {
		// CLICK URL
		ad.setClickURL(XML.getNodeTextCumulative(doc.getElementsByTagName("clickUrl")));
	}

}

NexAgeAdGrabber


/**
 * Copyright: Creative Common Attribution http://creativecommons.org/licenses/by/3.0/
 */
public class NexAgeAdGrabber extends AdGrabber {

	public NexAgeAdGrabber(HashTableExt adFieldPropertyBag) {
		super(adFieldPropertyBag);
	}

	/* ------------------------------------------			PUBLISHING CONSTANTS			------------------------------------------*/

	private static final String SITE_ID = "YOUR_SITE_ID";

	/* ------------------------------------------											------------------------------------------*/

	/**
	 *
	 * @param adFieldPropertyBag
	 * @return
	 * 			- The URL to be sent to the advertising web service
	 */
	protected String getRequestURL(HashTableExt adFieldPropertyBag) {
		StringBuffer sb = new StringBuffer("http://admax.nexage.com/adServe?");

		sb.append("dcn=" + SITE_ID);

		sb.append("&pos=" + getAdPosition(adFieldPropertyBag));

		sb.append("&ip=" + URLTools.urlEncodeBBForum(BBInfo.getIP())); // device IP

		sb.append("&ua=" + URLTools.urlEncodeBBForum(BBInfo.getUserAgent())); // device USER AGENT

		sb.append("&f=" + "xml");

		sb.append("&u(id)=" + BBInfo.getUniqueDeviceHash());

		return sb.toString();
	}

	private static String getAdPosition(HashTableExt adFieldPropertyBag) {
		if (adFieldPropertyBag != null && adFieldPropertyBag.get(AdAllocManager.AD_POSITION) != null) { //if we specified the ad position - return the specified ad position
			return (String) adFieldPropertyBag.get(AdAllocManager.AD_POSITION);
		} else {
			// otherwise, use the "imageonly" or "textonly", depending on the display size, or manual override
			return (BBInfo.isTallScreen() || (adFieldPropertyBag != null && adFieldPropertyBag.get(AdAllocManager.FETCH_IMAGE_ADS) != null)) ? "imageonly" : "textonly";
		}
	}

	protected boolean gotProperAd(Document doc) throws Exception {
		Node adsNode = doc.getElementsByTagName("ads").item(0);
		if (adsNode != null) {
			int adCount = Integer.parseInt(XML.getAttributeValue(adsNode, "count"));
			return adCount > 0;
		} else {
			return false;
		}
	}

	protected ImageAd parseImageAd(Document doc) throws Exception {
		ImageAd ad = new ImageAd();
		parseCommonAdValues(ad, doc);

		//parse the IMAGE of the banner
		String imageURL = XML.getAttributeValue(doc.getElementsByTagName("ad:content").item(0), "url");

		EncodedImage bannerImage = EncodedImage.createEncodedImage(StreamUtils.readRemoteStream(imageURL).getBytes(), 0, -1);
		ad.setImage(bannerImage);

		return ad;
	}

	protected TextAd parseTextAd(Document doc) throws Exception {
		TextAd ad = new TextAd();
		parseCommonAdValues(ad, doc);

		//parse the TEXT of the banner
		ad.setText(XML.getTextFromNode(doc.getElementsByTagName("ad:text").item(0)));

		return ad;
	}

	protected boolean shouldParseAsImageAd(Document doc) throws Exception {
		Node node = doc.getElementsByTagName("ad:group").item(0);
		String adType = XML.getAttributeValue(node, "type");

		return adType.toLowerCase().compareTo("banner") == 0;
	}

	/**
	 * Parse common values from the responce like the:
	 *  - tracking pixels/beacons
	 *  - the click URL
	 *
	 * @param ad
	 * @param doc
	 */
	private void parseCommonAdValues(Ad ad, Document doc) {
		// CLICK URL
		ad.setClickURL(XML.getTextFromNode(doc.getElementsByTagName("link").item(0)));

		// TRACKING PIXEL URLs - get only ones from the FIRST  node (in case there are more than 1 ad in the response, only the first should be processed and the rest ignored)
		Node adEventsNode = doc.getElementsByTagName("ad:events").item(0);
		NodeList nl = adEventsNode.getChildNodes();

		for (int i = 0; i < nl.getLength(); i++) {
			// If the tracking is of the "display" type - it is a tracking PIXEL URL
			if (XML.getAttributeValue(nl.item(i), "type").toLowerCase().compareTo("display") == 0) {
				String nodeName = nl.item(i).getFirstChild().getNodeName();
				if (nodeName.toLowerCase().compareTo("link") == 0) {
					String trackingPx = XML.getTextFromNode(nl.item(i).getFirstChild());
					ad.addTrackingPixelURL(trackingPx);
				}
			}
			// otherwise, if it is of the "click" type - it is a CLICK tracking URL
			else if (XML.getAttributeValue(nl.item(i), "type").toLowerCase().compareTo("click") == 0) {
				String nodeName = nl.item(i).getFirstChild().getNodeName();
				if (nodeName.toLowerCase().compareTo("link") == 0) {
					String trackingPx = XML.getTextFromNode(nl.item(i).getFirstChild());
					ad.addClickTrackingURL(trackingPx);
				}
			}
		}
	}

}

SomaAdGrabber


/**
 * Copyright © Comitic Software
 */
public class SOMAAdGrabber extends AdGrabber {

	public SOMAAdGrabber(HashTableExt adFieldPropertyBag) {
		super(adFieldPropertyBag);
	}

	/* ------------------------------------------			PUBLISHING CONSTANTS			------------------------------------------*/
	private static final String AD_SPACE = "YOUR_AD_SPACE";

	private static final String PUBLISHER_ID = "YOUR_PUB_ID";

	private static final String SOMA_API_VER = "somaapi-318"; //This is the version of the API I used

	/* ------------------------------------------											------------------------------------------*/

	/**
	 *
	 * @param overrideImageAds
	 * @return
	 * 			- The URL to be sent to the advertising web service
	 */
	protected String getRequestURL(HashTableExt adFieldPropertyBag) {
		StringBuffer sb = new StringBuffer("http://soma.smaato.net/oapi/reqAd.jsp?");

		sb.append("adspace=" + AD_SPACE);

		sb.append("&pub=" + PUBLISHER_ID);

		sb.append("&client=" + SOMA_API_VER);

		sb.append("&devip=" + URLTools.urlEncodeBBForum(BBInfo.getIP())); // device IP

		sb.append("&device=" + URLTools.urlEncodeBBForum(BBInfo.getUserAgent())); // device USER AGENT

		String adMode = (BBInfo.isTallScreen() || (adFieldPropertyBag!=null && adFieldPropertyBag.get(AdAllocManager.FETCH_IMAGE_ADS) != null)) ? "all" : "txt"; // "all" = IMAGE and TEXT; "txt" = TEXT only
		sb.append("&format=" + adMode);

		sb.append("&ownid=" + BBInfo.getUniqueDeviceHash());

		sb.append("&responce=" + "xml");

		return sb.toString();
	}

	protected boolean gotProperAd(Document doc) throws Exception {
		//return ((NodeList) doc.getElementsByTagName("ads")).getLength() > 0 && canProcessTheAd(doc);
		NodeList nl = ((NodeList) doc.getElementsByTagName("ads"));
		if (nl != null) {
			return nl.getLength() > 0  && canProcessTheAd(doc);
		} else {
			return false;
		}
	}

	private boolean canProcessTheAd(Document doc) {
		Node node = doc.getElementsByTagName("action").item(0);
		String actionType = XML.getAttributeValue(node, "type");
		return actionType.toLowerCase().compareTo("link") == 0;
	}

	protected ImageAd parseImageAd(Document doc) throws Exception {
		ImageAd ad = new ImageAd();
		parseCommonAdValues(ad, doc);

		//parse the IMAGE of the banner
		String imageURL = XML.getNodeTextCumulative(doc.getElementsByTagName("link"));

		EncodedImage bannerImage = EncodedImage.createEncodedImage(StreamUtils.readRemoteStream(imageURL).getBytes(), 0, -1);
		ad.setImage(bannerImage);

		return ad;
	}

	protected TextAd parseTextAd(Document doc) throws Exception {
		TextAd ad = new TextAd();
		parseCommonAdValues(ad, doc);

		//parse the TEXT of the banner
		ad.setText(XML.getTextFromNode(doc.getElementsByTagName("adtext").item(0)));

		return ad;
	}

	protected boolean shouldParseAsImageAd(Document doc) throws Exception {
		Node node = doc.getElementsByTagName("ad").item(0);
		String adType = XML.getAttributeValue(node, "type");

		return adType.toLowerCase().compareTo("img") == 0;

	}

	/**
	 * Parse common values from the responce like the:
	 *  - tracking pixels/beacons
	 *  - the click URL
	 *
	 * @param ad
	 * @param doc
	 */
	private void parseCommonAdValues(Ad ad, Document doc) {
		// CLICK URL
		ad.setClickURL(XML.getAttributeValue(doc.getElementsByTagName("action").item(0), "target"));

		//TRACKING PIXEL URLs = the BEACONs as they are named in SMAATO network
		NodeList nl = doc.getElementsByTagName("beacon");
		for (int i = 0; i < nl.getLength(); i++) {
			String trackingPx = XML.getTextFromNode(nl.item(i));
			ad.addTrackingPixelURL(trackingPx);
		}
	}

}

Please let me know in the comments if you find this useful!