USRE-84 Client API project CVS source commit

This commit is contained in:
YuCheng Hu 2021-11-24 13:04:26 -05:00
commit 55ba0f4483
No known key found for this signature in database
GPG Key ID: C395DC68EF030B59
34 changed files with 2865 additions and 0 deletions

11
build.properties Normal file
View File

@ -0,0 +1,11 @@
#
# Properties file for commons build.xml
#
src=src
etc=src/etc
libsrc=src/lib
javadoc=src/javadoc
build=target
classes=target/classes
libdir=target/lib

75
build.xml Normal file
View File

@ -0,0 +1,75 @@
<project name="retsAPI" default="jar" basedir=".">
<property file="build.properties"/>
<path id="java.classpath">
<fileset dir="${libdir}">
<include name="*.jar"/>
</fileset>
</path>
<target name="clean">
<delete dir="${build}"/>
</target>
<target name="init">
<tstamp/>
<mkdir dir="${build}"/>
<mkdir dir="${classes}"/>
<mkdir dir="${libdir}"/>
</target>
<target name="copy-deps" depends="init">
<copy file="${libsrc}/regexp-1.2.jar" tofile="${libdir}/regexp-1.2.jar" />
<copy file="${libsrc}/log4j-1.2.5.jar" tofile="${libdir}/log4j-1.2.5.jar" />
<copy file="${libsrc}/BZip2.jar" tofile="${libdir}/BZip2.jar" />
<copy file="${libsrc}/commons-httpclient-2.0-rc1-avantia.jar" tofile="${libdir}/commons-httpclient-2.0-rc1-avantia.jar" />
<copy file="${libsrc}/retsCommons.jar" tofile="${libdir}/retsCommons.jar" />
<copy file="${libsrc}/mail.jar" tofile="${libdir}/mail.jar" />
<copy file="${libsrc}/activation.jar" tofile="${libdir}/activation.jar" />
</target>
<target name="compile" depends="copy-deps">
<javac srcdir="${src}" destdir="${classes}" debug="on">
<classpath refid="java.classpath"/>
<include name="main/java/org/realtor/**/*.java"/>
<exclude name="*.java"/>
</javac>
<copy todir="${classes}">
<fileset dir="${etc}">
<include name="*.dtd" />
<include name="*.properties" />
<include name="*.xml" />
<include name="*.xsl" />
</fileset>
</copy>
</target>
<target name="javadoc">
<javadoc packagenames="org.realtor.rets.*"
sourcepath="${src}"
defaultexcludes="yes"
destdir="doc"
classpathref="java.classpath"
author="true"
version="true"
use="true"
private="Yes"
windowtitle="RETS 1.5 Reference Impl">
<doctitle>
<![CDATA[<h1>RETS 1.5</h1>]]></doctitle>
<bottom>
<![CDATA[<i>Copyright &#169; 2002 National Association of Realtors - All Rights Reserved.</i>]]></bottom>
<link href="http://developer.java.sun.com/developer/products/xml/docs/api/"/>
</javadoc>
</target>
<target name="jar" depends="clean, compile">
<delete file="${build}/retsAPI.jar"/>
<jar jarfile="${build}/retsAPI.jar">
<fileset dir="${classes}">
</fileset>
</jar>
</target>
</project>

7
project.properties Normal file
View File

@ -0,0 +1,7 @@
# JAR FILES
maven.jar.override=on
maven.jar.BZip2=${basedir}/src/lib/BZip2.jar
maven.jar.retscommons=${basedir}/src/lib/retsCommons.jar
maven.jar.log4j=${basedir}/src/lib/log4j-1.2.5.jar
maven.jar.commons-httpclient=${basedir}/src/lib/commons-httpclient-2.0-rc1-avantia.jar
maven.jar.regexp=${basedir}/src/lib/regexp.jar

115
project.xml Normal file
View File

@ -0,0 +1,115 @@
<?xml version="1.0"?>
<project>
<extend>${maven.base.project}</extend>
<pomVersion>3</pomVersion>
<name>RETS API</name>
<id>retsapi</id>
<currentVersion>1.0</currentVersion>
<inceptionYear>2003</inceptionYear>
<package>org.realtor.rets</package>
<logo>/images/logos/rets_suite.jpg</logo>
<shortDescription>
Java RETS API
</shortDescription>
<description>
The RETS API is a Reference Implementation API for RETS Transactions
written in Java and can be used as an API by web-based and desktop
RETS Client Applications.
</description>
<url>/sandbox/${pom.artifactId}/</url>
<versions>
<version>
<id>release</id>
<name>1.0</name>
<tag>RETSAPI</tag>
</version>
</versions>
<dependencies>
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.5</version>
<url>http://www.ibiblio.org/maven/log4j</url>
</dependency>
<dependency>
<groupId>commons-httpclient</groupId>
<artifactId>commons-httpclient</artifactId>
<version>2.0-rc1</version>
<url>http://www.ibiblio.org/maven/commons-httpclient</url>
</dependency>
<dependency>
<groupId>regexp</groupId>
<artifactId>regexp</artifactId>
<version>1.2</version>
<url>http://www.ibiblio.org/maven/regexp</url>
</dependency>
<dependency>
<groupId>BZip2</groupId>
<artifactId>BZip2</artifactId>
<version>1.0</version>
<url></url>
</dependency>
<dependency>
<groupId>retscommons</groupId>
<artifactId>retscommons</artifactId>
<version>1.0</version>
<url></url>
</dependency>
</dependencies>
<build>
<nagEmailAddress>
rets@avantia-inc.com
</nagEmailAddress>
<sourceDirectory>${basedir}/src</sourceDirectory>
<!-- J A R R E S O U R C E S -->
<!-- Resources that are packaged up inside the JAR file -->
<resources>
<resource>
<directory>${basedir}/lib</directory>
<includes>
<include>*.jar</include>
</includes>
</resource>
<resource>
<directory>${basedir}/src/resources/misc</directory>
<includes>
<include>*.xsd</include>
</includes>
</resource>
<resource>
<directory>${basedir}/config</directory>
<includes>
<include>log4j.properties</include>
</includes>
</resource>
</resources>
<!-- Integration unit test cases -->
<integrationUnitTest/>
<jars>
</jars>
</build>
<reports>
<report>maven-changelog-plugin</report>
<report>maven-changes-plugin</report>
<report>maven-checkstyle-plugin</report>
<report>maven-developer-activity-plugin</report>
<report>maven-file-activity-plugin</report>
<report>maven-jdepend-plugin</report>
<report>maven-junit-report-plugin</report>
<report>maven-jxr-plugin</report>
<report>maven-pmd-plugin</report>
<report>maven-tasklist-plugin</report>
</reports>
</project>

3
src/etc/dummy.dtd Normal file
View File

@ -0,0 +1,3 @@
DO NOT REMOVE!
This file is search for as a resource.
All other DTDs should be in the same directory as this file.

38
src/etc/log4j.properties Normal file
View File

@ -0,0 +1,38 @@
log4j.rootCategory=error, stdout
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%5p [%t] (%F:%L) - %m%n
# client API logfile
log4j.appender.R1=org.apache.log4j.RollingFileAppender
log4j.appender.R1.File=/tmp/retsClientAPI.log
log4j.appender.R1.MaxFileSize=100KB
log4j.appender.R1.MaxBackupIndex=3
log4j.appender.R1.layout=org.apache.log4j.PatternLayout
log4j.appender.R1.layout.ConversionPattern=%p %t %c CLIENTAPI- %m%n
# server logfile
log4j.appender.R2=org.apache.log4j.RollingFileAppender
log4j.appender.R2.File=/tmp/retsServer.log
log4j.appender.R2.MaxFileSize=100KB
log4j.appender.R2.MaxBackupIndex=3
log4j.appender.R2.layout=org.apache.log4j.PatternLayout
log4j.appender.R2.layout.ConversionPattern=%p %t %c SERVER - %m%n
# setup RETS client API logging
log4j.category.org.realtor.rets.retsapi=debug, R1
log4j.category.org.realtor.rets.util=debug, R1
# setup RETS server logging
log4j.category.org.realtor.rets.server=debug, R2, stdout
log4j.category.org.realtor.rets.util=debug, R2
log4j.category.org.realtor.rets.persistance=error, R2
log4j.additivity.org.realtor.rets.server=false
log4j.additivity.org.realtor.rets.retsapi=false
log4j.additivity.org.realtor.rets.util=false

BIN
src/lib/BZip2.jar Normal file

Binary file not shown.

BIN
src/lib/activation.jar Normal file

Binary file not shown.

Binary file not shown.

Binary file not shown.

BIN
src/lib/commons-logging.jar Normal file

Binary file not shown.

BIN
src/lib/commons-rets.jar Normal file

Binary file not shown.

BIN
src/lib/log4j-1.2.5.jar Normal file

Binary file not shown.

BIN
src/lib/mail.jar Normal file

Binary file not shown.

BIN
src/lib/regexp-1.2.jar Normal file

Binary file not shown.

BIN
src/lib/regexp.jar Normal file

Binary file not shown.

BIN
src/lib/retsCommons.jar Normal file

Binary file not shown.

View File

@ -0,0 +1,126 @@
package org.realtor.rets.retsapi;
import javax.activation.DataSource;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.Vector;
/**
* A class to provide a {@link javax.activation.DataSource} interface to
* an input stream of unknown characteristics. The <code>DataSource</cdoe>
* interface requires that its implementor be able to repeatedly restart
* the read from the beginning. This isn't guaranteed by InputStream, so
* we encapsulate the InputStream with an object that will buffer the
* data coming from it. (We can't use <code>mark</code>/<code>reset</code>
* because the eventual data source consumer might use those methods,
* which would override use here.
*/
public class InputStreamDataSource implements DataSource
{
private byte fStreamBytes[];
private String fContentType;
public InputStreamDataSource(InputStream baseStream, String contentType) throws IOException {
fContentType = contentType;
// Read the content of the input stream into byte array blocks. Read
// to the end of file and save all the blocks. These will be consolidated
// after all are read. This uses twice as much storage as simply designing
// a new input stream, but I don't want to write that class right now,
// especially since I'm not completely clear on the blocking semantics.
// ByteArrayInputStream already knows them, so I'll just use that.
Vector byteArrays = new Vector();
int totalBytesRead = 0;
byte temporaryByteArray[];
int readCount;
int quantum = 4096;
int bytesInCurrentBlock;
do {
bytesInCurrentBlock = 0;
temporaryByteArray = new byte[quantum];
do {
readCount =
baseStream.read(temporaryByteArray, bytesInCurrentBlock, quantum - bytesInCurrentBlock);
if (readCount > 0) bytesInCurrentBlock += readCount;
} while (readCount >= 0 && bytesInCurrentBlock < quantum);
if (bytesInCurrentBlock > 0)
byteArrays.add(temporaryByteArray);
totalBytesRead += bytesInCurrentBlock;
} while (readCount >= 0);
// Copy all the blocks into one single mondo block.
fStreamBytes = new byte[totalBytesRead];
int numberOfBlocks = byteArrays.size();
byte theBlock[];
for (int blockIndex = 0; blockIndex < numberOfBlocks - 1; ++blockIndex) {
theBlock = (byte[]) byteArrays.get(blockIndex);
System.arraycopy(theBlock, 0, fStreamBytes, blockIndex * quantum, quantum);
}
theBlock = (byte[]) byteArrays.get(numberOfBlocks - 1);
System.arraycopy(theBlock, 0, fStreamBytes, quantum * (numberOfBlocks - 1), bytesInCurrentBlock);
}
/**
* Returns the Content-Type header value for the encapsulated content.
*/
public String getContentType() {
return fContentType;
}
/**
* Returns an input stream that may be used to access the content of this
* <code>DataSource</code> A new input stream, set at the beginning of the
* stream, is returned each time you call this method.
*
* @return An {@link InputStream} that will furnish the
* associated data.
*/
public InputStream getInputStream() {
return new ByteArrayInputStream(fStreamBytes);
}
/**
* Returns the name of this data source. This class does not provide named data
* sources; the string "Untitled" is returned.
*
* @return The string "Untitled".
*/
public String getName() {
return "Untitled";
}
/**
* Conformance to <code>javax.activation.DataSource</code> Throws an
* {@link IOException} since this DataSource is read-only.
*/
public OutputStream getOutputStream() throws IOException {
throw new IOException("InputStreamDataSource is read-only.");
}
/**
* Return the content of the input stream as a full byte array.
*/
public byte[] contentAsByteArray() {
return fStreamBytes;
}
/**
* Returns the loaded data as a string. This is primarily for diagnostic
* purposes, as there are other ways of turning an InputStream into a String.
*
* @return A <code>String</code> containing the input data.
*/
public String bufferedDataAsString() {
return new String(fStreamBytes);
}
}

View File

@ -0,0 +1,34 @@
package org.realtor.rets.retsapi;
import org.apache.log4j.*;
/**
* RETSActionTransaction.java
*
* This class is used to build an action transaction
*
* @author jbrush
* @version 1.0
*/
public class RETSActionTransaction extends RETSTransaction {
static Category cat = Category.getInstance(RETSConnection.class);
/**
* Constructor
*/
public RETSActionTransaction() {
super();
setRequestType("Action");
}
/**
* Sets the reponse body.
*
*@param body text of the response
*
*/
public void setResponse(String body) {
super.setResponse(body);
}
}

View File

@ -0,0 +1,128 @@
//
// RETSBasicResponseParser.java
// NARRETSClasses
//
// Created by Bruce Toback on 1/3/05.
// Copyright (c) 2005 __MyCompanyName__. All rights reserved.
//
package org.realtor.rets.retsapi;
import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.SAXParseException;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;
import java.io.InputStream;
import java.util.Vector;
/**
* Do a basic parse of a RETS response, optionally failing fast upon determination
* as to whether this is actually a RETS response.
*/
public class RETSBasicResponseParser extends org.xml.sax.helpers.DefaultHandler
{
protected String fReplyText;
protected int fReplyCode;
protected Vector fExceptions;
protected StringBuffer fElementCharacters;
protected boolean fReplyValid;
protected boolean fFirstElementProcessed; // Set once the first element is processed
public RETSBasicResponseParser(InputStream responseStream) {
fReplyValid = false;
try {
SAXParserFactory aParserFactory = SAXParserFactory.newInstance();
aParserFactory.setValidating(false);
aParserFactory.setNamespaceAware(true);
SAXParser aParser = aParserFactory.newSAXParser();
aParser.parse(responseStream, this);
} catch (SAXParseException saxParseException) {
addExceptionMessage(saxParseException.getMessage());
} catch (SAXException saxException) {
addExceptionMessage(saxException.getMessage());
} catch (ParserConfigurationException parserConfigurationException) {
addExceptionMessage(parserConfigurationException.getMessage());
} catch (java.io.IOException ioException) {
addExceptionMessage(ioException.getMessage());
}
}
public boolean responseIsValid() {
return fReplyValid && (fExceptions == null || fExceptions.size() == 0);
}
public Vector exceptionMessages() {
return fExceptions;
}
public int replyCode() {
return fReplyCode;
}
public String replyText() {
return fReplyText;
}
protected void addExceptionMessage(String exceptionMessage) {
if (fExceptions == null)
fExceptions = new Vector();
fExceptions.addElement(exceptionMessage);
}
// Methods required to extend DefaultHandler
public void error(SAXParseException e) {
addExceptionMessage(e.getMessage());
}
public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {
int attributeCount = attributes.getLength();
int attributeIndex;
String attributeName;
if (fElementCharacters == null)
fElementCharacters = new StringBuffer();
else
fElementCharacters.setLength(0);
if (qName.equals("RETS") ||
qName.equals("RETS-STATUS")) {
for (attributeIndex = 0; attributeIndex < attributeCount; ++attributeIndex) {
attributeName = attributes.getLocalName(attributeIndex);
if (attributeName.equals("ReplyText"))
fReplyText = attributes.getValue(attributeIndex);
else if (attributeName.equals("ReplyCode")) {
String replyCode = attributes.getValue(attributeIndex);
try {
fReplyCode = Integer.parseInt(replyCode);
fReplyValid = true;
} catch (NumberFormatException e) {
fReplyCode = 0;
addExceptionMessage("RETS reply code invalid (\"" + replyCode + "\")");
}
}
}
} else if (!fFirstElementProcessed) {
throw new SAXException("Not a RETS reply.");
}
fFirstElementProcessed = true;
}
public void endElement(String uri, String localName, String qName) {
}
public void characters(char[] ch, int start, int length) {
fElementCharacters.append(ch, start, length);
}
}

View File

@ -0,0 +1,168 @@
package org.realtor.rets.retsapi;
import org.apache.log4j.*;
import org.realtor.rets.util.*;
import java.security.*;
/**
* Send a Change Password transaction to the server.
*
* @author jbrush
* @version 1.0
*/
public class RETSChangePasswordTransaction extends RETSTransaction {
static Category cat = Category.getInstance(RETSChangePasswordTransaction.class);
private String oldPassword = null;
private String newPassword = null;
private String newPassword2 = null;
private String encrypted = null;
private String decrypted = null;
private String username = null;
/** Create a new RETSChangePasswordTransaction */
public RETSChangePasswordTransaction() {
super();
setRequestType("ChangePassword");
}
/**
* Sets the username
*@param username name user signs in with
*/
public void setUsername(String username) {
this.username = username;
}
/**
* Sets the old password
*@param passwd users password to be changed
*/
public void setOldPassword(String passwd) {
this.oldPassword = passwd;
}
/**
* Sets the new password value
*@param passwd new password
*/
public void setNewPassword(String passwd) {
this.newPassword = passwd;
}
/**
* Sets the new password confirm value
*@param passwd new password
*/
public void setNewPassword2(String passwd) {
this.newPassword2 = passwd;
}
/**
* process the transaction
*/
public void preprocess() {
String errMsg = null;
super.preprocess();
setUsername((String) transactionContext.get("username"));
cat.debug("username=" + username);
cat.debug("oldPassword=" + oldPassword);
cat.debug("newPassword=" + newPassword);
//cat.debug("newPassword2="+newPassword2);
/*if (oldPassword == null
|| !oldPassword.equals(transactionContext.get("password"))) {
errMsg = "Old Password does not match.";
}
else if ((newPassword1 == null || newPassword2 == null)
|| (!newPassword1.equals(newPassword2))) {
errMsg = "New Passwords do not match.";
}*/
//else {
String pwd = encryptPWD();
//cat.debug("PWD:"+pwd);
setRequestVariable("PWD", pwd);
//}
if (errMsg != null) {
cat.warn(errMsg);
setResponseStatus("20513"); // Miscellaneous error
setResponseStatusText(errMsg);
setResponse(errMsg);
errMsg = null;
}
}
public void postprocess() {
transactionContext.put("password", newPassword);
}
private String encryptPWD() {
byte[] key = makeKey();
String source = newPassword + ":" + username;
return DES(key, source);
}
private String DES(byte[] keyBytes, String source) {
try {
// Create encrypter/decrypter class
DesCrypter crypter = new DesCrypter(keyBytes);
// Encrypt
encrypted = crypter.encrypt(source);
// Decrypt
decrypted = crypter.decrypt(encrypted);
return encrypted;
} catch (Exception e) {
}
return null;
}
private byte[] makeKey() {
MessageDigest md = null;
try {
md = MessageDigest.getInstance("MD5");
} catch (java.security.NoSuchAlgorithmException e) {
e.printStackTrace();
}
md.reset();
// trim to 8 bytes
byte[] key = new byte[8];
System.arraycopy(md.digest((oldPassword + username).toUpperCase()
.getBytes()), 0, key, 0, 8);
return key;
}
/////////////////////////////////////////////////
public static void main(String[] args) {
RETSChangePasswordTransaction t = new RETSChangePasswordTransaction();
t.setUsername(args[0]);
t.setOldPassword(args[1]);
t.setNewPassword(args[2]);
//t.setNewPassword2(args[2]);
t.preprocess();
System.out.println("encrypted=" + t.encrypted);
System.out.println("decrypted=" + t.decrypted);
}
}

View File

@ -0,0 +1,633 @@
/*
* RETSConnection.java
*
* Created on November 16, 2001, 1:33 PM
*/
package org.realtor.rets.retsapi;
import com.aftexsw.util.bzip.CBZip2InputStream;
import org.apache.commons.httpclient.*;
import org.apache.commons.httpclient.cookie.CookiePolicy;
import org.apache.commons.httpclient.methods.GetMethod;
import org.apache.commons.httpclient.methods.PostMethod;
import org.apache.log4j.BasicConfigurator;
import org.apache.log4j.Category;
import org.realtor.rets.util.RETSConfigurator;
import java.io.*;
import java.net.URLEncoder;
import java.util.*;
import java.util.zip.GZIPInputStream;
/**
* Provides a connection to a RETSServer.
*
* @author tweber
* @version 1.0
*/
public class RETSConnection extends java.lang.Object {
// log4j category
static Category cat = Category.getInstance(RETSConnection.class);
static {
RETSConfigurator.configure();
}
//Key value pairs for request header.
private HashMap headerHash = new HashMap();
private HashMap responseHeaderMap = new HashMap();
private String serverUrl = null;
private String errMsg = null;
private boolean isRetryingAuthorization = false;
private boolean gzipCompressed = false;
private boolean bzipCompressed = false;
private boolean STREAMRESPONSE = false;
private long lastTransactionTime = 0;
private String transactionLogDirectory = null;
private String imageAccept = "image/gif"; // default
private PrintWriter log = null;
private HttpClient client = new HttpClient();
HashMap transactionContext = new HashMap(); // holds data across transactions
private int connTimeoutSeconds = 60; // 60 seconds default
/**
* Creates new RETSConnection and changes default connection timeout
* and sets the ServerURL.
*/
public RETSConnection(String url, int connTimeoutSeconds) {
this(url);
this.connTimeoutSeconds = connTimeoutSeconds;
}
/**
* Creates new RETSConnection and changes default connection timeout
* and sets the ServerURL.
*/
public RETSConnection(int connTimeoutSeconds) {
this();
this.connTimeoutSeconds = connTimeoutSeconds;
}
/**
* Creates new RETSConnection and sets the ServerURL.
*/
public RETSConnection(String url) {
this();
serverUrl = url;
}
/**
* Create a new RETSConnection and setup some required Header fields.
*/
public RETSConnection() {
setRequestHeaderField("User-Agent", "Mozilla/4.0");
setRequestHeaderField("RETS-Version", "RETS/1.0");
}
/**
* Executes a transaction
*
* @param RETSTransaction transaction to execute
*/
public void execute(RETSTransaction transaction) {
execute(transaction, false);
}
/**
* Executes a transaction
*
* @param RETSTransaction transaction to execute
*/
public void executeStreamResponse(RETSTransaction transaction) {
execute(transaction, true);
}
/**
* Executes a transaction
*
* @param RETSTransaction transaction to execute
*/
public void execute(RETSTransaction transaction, boolean asStream) {
java.util.Date dt1 = new Date();
STREAMRESPONSE = asStream;
if ( transaction instanceof RETSGetObjectTransaction ) {
setRequestHeaderField("Accept", getImageAccept());
} else {
setRequestHeaderField("Accept", "*/*");
}
if ((transactionLogDirectory != null) && (transactionLogDirectory.length() > 1)) {
String transType = transaction.getClass().getName();
int nameIdx = transType.lastIndexOf(".") + 1;
String name = transType.substring(nameIdx);
Date dt = new Date();
String outFile = transactionLogDirectory + "/" + name + dt.getTime() + ".txt";
try {
log = new PrintWriter(new FileWriter(outFile));
log.println("<!-- RETS REQUEST -->");
} catch (Exception e) {
cat.error("could create output file :" + outFile);
}
}
String compressFmt = transaction.getCompressionFormat();
if (compressFmt != null) {
if (compressFmt.equalsIgnoreCase("gzip")) {
setRequestHeaderField("Accept-Encoding", "application/gzip,gzip");
} else if (compressFmt.equalsIgnoreCase("bzip")) {
setRequestHeaderField("Accept-Encoding", "application/bzip,bzip");
} else if (compressFmt.equalsIgnoreCase("none")) {
removeRequestHeaderField("Accept-Encoding");
}
}
transaction.setContext(transactionContext);
transaction.preprocess();
processRETSTransaction(transaction);
transaction.postprocess();
Date dt2 = new Date();
lastTransactionTime = dt2.getTime() - dt1.getTime();
if (log != null) {
try {
log.close();
} catch (Exception e) {
e.printStackTrace();
}
log = null;
}
return;
}
public long getLastTransactionTime() {
return lastTransactionTime;
}
public void setTransactionLogDirectory(String tLogDir) {
this.transactionLogDirectory = tLogDir;
}
public String getTransactionLogDirectory() {
return this.transactionLogDirectory;
}
private void writeToTransactionLog(String msg) {
if (log != null) {
try {
this.log.println(msg);
} catch (Exception e) {
e.printStackTrace();
}
}
cat.debug(msg);
}
private void writeMapToTransactionLog(Map map) {
if (map == null) {
return;
}
Iterator itr = map.keySet().iterator();
while (itr.hasNext()) {
String key = (String) itr.next();
String value = "";
Object obj = map.get(key);
if (obj instanceof String) {
value = (String) obj;
} else {
value = "{ ";
Collection c = (Collection) obj;
Iterator i2 = c.iterator();
if (i2.hasNext()) {
value = (String) i2.next();
while (i2.hasNext()) {
value = value + ", " + (String) i2.next();
}
}
value = value + " }";
}
writeToTransactionLog(key + "=" + value);
}
}
/**
* Returns the server's URL, this url as a base for all transactions
*/
public String getServerUrl() {
return serverUrl;
}
/**
* Sets the url for the connection.
*
* @param url Server's address ex: http://www.realtor.org/RETSServer
*/
public void setServerUrl(String url) {
serverUrl = url;
}
/**
* Key value pairs in the client request header
*
* @param key field name in the request header
* @param value value associated with the key
*/
public void setRequestHeaderField(String key, String value) {
headerHash.put(key, value);
}
public void setUserAgent(String userAgent) {
headerHash.put("User-Agent", userAgent);
}
public void setRetsVersion(String retsVersion) {
setRequestHeaderField("RETS-Version", retsVersion);
}
/**
* Removes a key/value pair from the request header.
*
* @param key field to remove from the request header.
*/
public void removeRequestHeaderField(String key) {
headerHash.remove(key);
}
public HashMap getResponseHeaderMap() {
return responseHeaderMap;
}
/**
* gets the url content and returns an inputstream
*
* @param strURL
* @param requestMethod
* @param requestMap
*/
public InputStream getURLContent(String strURL, String requestMethod, Map requestMap) {
InputStream is = null;
gzipCompressed = false;
bzipCompressed = false;
boolean needToAuth = false;
HttpMethod method = null;
cat.debug("getURLContent: URL=" + strURL);
try {
if (requestMethod.equalsIgnoreCase("GET")) {
method = new GetMethod(strURL);
} else {
method = new PostMethod(strURL);
}
client.getState().setCredentials(null, null, new UsernamePasswordCredentials(getUsername(), getPassword()));
client.getState().setCookiePolicy(CookiePolicy.COMPATIBILITY);
client.setConnectionTimeout(connTimeoutSeconds * 1000);
method.setDoAuthentication(true);
method.setFollowRedirects(true);
addHeaders(method, headerHash);
writeMapToTransactionLog(headerHash);
// send the request parameters
if (requestMap != null) {
NameValuePair[] pairs = mapToNameValuePairs(requestMap);
if (requestMethod.equalsIgnoreCase("POST")) {
// requestMethod is a post, so we can safely cast.
PostMethod post = (PostMethod) method;
post.setRequestBody(pairs);
} else {
GetMethod get = (GetMethod) method;
get.setQueryString(pairs);
}
}
this.writeToTransactionLog("<!-- Response from server -->");
int responseCode = client.executeMethod(method);
ByteArrayOutputStream os = new ByteArrayOutputStream();
ByteArrayInputStream bais = new ByteArrayInputStream(method.getResponseBody());
copyResponseHeaders(method);
method.releaseConnection(); // from bruce
return bais;
} catch (IOException io) {
io.printStackTrace();
errMsg = "RETSAPI: I/O exception while processing transaction: " + io.getMessage();
return null;
} finally {
if (method != null) {
method.releaseConnection();
}
}
}
/**
* Changes a map into an array of name value pairs
*
* @param requestMap The map to change.
* @return An array of Name value pairs, representing keys and values from the map.
*/
private NameValuePair[] mapToNameValuePairs(Map requestMap) {
NameValuePair[] pairs = new NameValuePair[requestMap.size()];
Iterator iter = requestMap.keySet().iterator();
int i = 0;
while (iter.hasNext()) {
String key = (String) iter.next();
String value = (String) requestMap.get(key);
NameValuePair nvp = new NameValuePair(key, value);
pairs[i] = nvp;
i++;
}
return pairs;
}
/**
* Adds response headers to Http method
*
* @param responseHeaderMap
* @param method
*/
private void copyResponseHeaders(HttpMethod method) {
responseHeaderMap.clear();
Header[] headers = method.getResponseHeaders();
for (int i = 0; i < headers.length; i++) {
Header current = headers[i];
List list = (List) responseHeaderMap.get(current.getName());
if (list == null) {
list = new ArrayList();
}
list.add(current.getValue());
responseHeaderMap.put(current.getName(), list);
}
}
private void addHeaders(HttpMethod method, HashMap headers) {
Iterator keys = headers.keySet().iterator();
while (keys.hasNext()) {
String key = (String) keys.next();
Object value = headers.get(key);
if (value instanceof String && isValidString((String) value)) {
method.addRequestHeader(key, (String) value);
} else if (value instanceof ArrayList) {
ArrayList list = (ArrayList) value;
StringBuffer valueList = new StringBuffer();
for (int i = 0; i < list.size(); i++) {
if (i > 0) {
valueList.append(";");
}
valueList.append(list.get(i));
}
method.addRequestHeader(key, valueList.toString());
}
}
}
/**
* Processes a transaction, sends rets request and gets
* the response stream from the server. Uncompresses the
* response stream if compression was used in the reply
*
* @param transaction rets transaction to process
*/
private void processRETSTransaction(RETSTransaction transaction) {
try {
serverUrl = transaction.getUrl();
cat.debug(transaction.getRequestType() + " URL : {" + serverUrl + "}");
if (serverUrl == null) {
cat.error(transaction.getRequestType() + " URL is null");
transaction.setResponseStatus("20036");
transaction.setResponseStatusText(transaction.getRequestType() + " URL is missing. Successful login is required.");
return; // throw exception here
}
String method = "POST";
// Action transaction requires a GET according to RETS spec
if (transaction.getRequestType().equalsIgnoreCase("Action")) {
method = "GET";
}
cat.debug("method: " + method);
InputStream is = getURLContent(serverUrl, method, transaction.getRequestMap());
if (is == null) {
transaction.setResponseStatus("20513"); // Miscellaneous error
transaction.setResponseStatusText(errMsg);
transaction.setResponse(errMsg);
errMsg = null;
return;
} else {
Iterator itr = responseHeaderMap.keySet().iterator();
Object compressionFmt = responseHeaderMap.get("Content-Encoding");
if (compressionFmt != null) {
cat.debug("Header class : " + compressionFmt.getClass().getName());
if (compressionFmt.toString().equalsIgnoreCase("[gzip]")) {
gzipCompressed = true;
} else if (compressionFmt.toString().equalsIgnoreCase("[bzip]")) {
bzipCompressed = true;
}
}
if (gzipCompressed) {
is = new GZIPInputStream(is);
} else if (bzipCompressed) {
is = new CBZip2InputStream(is);
}
}
this.writeToTransactionLog("<!-- Obtained and Identified Response Stream -->");
transaction.setResponseHeaderMap(this.responseHeaderMap);
if ((transaction instanceof RETSGetObjectTransaction && (! transaction.getResponseHeader("Content-Type").startsWith("text/xml"))) || STREAMRESPONSE) {
transaction.setResponseStream(is);
} else {
String contents = null;
contents = streamToString(is);
writeToTransactionLog(contents);
/*catch( IOException e) {
errMsg = "Error reading response stream: " + contents;
cat.error(errMsg, e);
transaction.setResponseStatus("20513"); // Miscellaneous error
transaction.setResponseStatusText(errMsg);
errMsg = null;
}*/
if (contents.length() == 0) {
transaction.setResponseStatus("20513"); // Miscellaneous error
transaction.setResponseStatusText("Empty Body");
}
transaction.setResponse(contents);
}
} catch (Exception e) {
e.printStackTrace();
}
}
String getUsername() {
String username = null; //(String)requestMap.get("username");
if (username == null) {
username = (String) transactionContext.get("username");
}
return username;
}
String getPassword() {
String password = null; //(String)requestMap.get("password");
if (password == null) {
password = (String) transactionContext.get("password");
}
return password;
}
/**
* Removes the quotes on a string.
*
* @param quotedString string that might contain quotes
*/
private static String removeQuotes(String quotedString) {
if ((quotedString != null) && (quotedString.length() > 2)) {
return quotedString.substring(1, quotedString.length() - 1);
} else {
return ""; // empty string
}
}
/**
* Checks to make sure the string passed in is a valid string parameter (not null and not zero length).
*
* @param value string to be validated
*/
private boolean isValidString(String value) {
return ((value != null) && (value.length() > 0));
}
private String streamToString(InputStream is) throws IOException {
if (is != null) {
StringBuffer sb = new StringBuffer();
int numread = 0;
byte[] buffer = new byte[1024 * 8]; //initialize an 8k buffer
while ((numread = is.read(buffer)) >= 0) {
String s = new String(buffer, 0, numread);
sb.append(s);
}
return sb.toString();
}
return null;
}
/**
* Main method for testing only!
*
* @param args the command line arguments
*/
public static void main(String[] args) {
BasicConfigurator.configure();
RETSConnection rc = new RETSConnection();
RETSLoginTransaction trans = new RETSLoginTransaction();
try {
Properties props = new Properties();
props.load(new FileInputStream("/tmp/client.properties"));
// Add the optional request parameters if they exist, are non-null and non-zero-length
// rc.setRequestHeaderField("Authorization", (String)props.get("login.AUTHORIZATION"));
rc.setServerUrl((String) props.getProperty("SERVER_URL"));
trans.setUrl((String) props.getProperty("SERVER_URL"));
trans.setUsername((String) props.getProperty("USERNAME"));
trans.setPassword((String) props.getProperty("PASSWORD"));
} catch (Exception e) {
e.printStackTrace();
}
rc.execute(trans);
}
/**
* Build the queryString from the request map
*
* @param requestMap the list of request parameters
*/
private String buildQueryString(Map requestMap) {
/*if (((String)(requestMap.get("requestType"))).equalsIgnoreCase("Search")) {
return "SearchType=Property&Class=RESI&Query=(Listing_Price%3D100000%2B)&QueryType=DMQL";
}*/
StringBuffer sb = new StringBuffer();
Iterator it = requestMap.keySet().iterator();
// build query string
while (it.hasNext()) {
String key = (String) it.next();
if (key.equals("requestType")) {
//commenting out requestType because it is not a standard req parameter and may break RETS servers
continue;
}
String reqStr = key + "=" + URLEncoder.encode((String) requestMap.get(key));
cat.debug(reqStr);
sb.append(reqStr);
if (it.hasNext()) {
sb.append("&");
}
}
return sb.toString();
}
public String getImageAccept() {
return imageAccept;
}
public void setImageAccept(String imageAccept) {
this.imageAccept = imageAccept;
}
}

View File

@ -0,0 +1,52 @@
/**
* RETSGetMetadataTransaction.java
*
* @author jbrush
* @version
*/
package org.realtor.rets.retsapi;
//import java.util.*;
import org.apache.log4j.*;
///////////////////////////////////////////////////////////////////////
public class RETSGetMetadataTransaction extends RETSTransaction {
static Category cat = Category.getInstance(RETSGetMetadataTransaction.class);
String version = null;
/**
* constructor
*/
public RETSGetMetadataTransaction() {
super();
setRequestType("GetMetadata");
}
public void setType(String str) {
setRequestVariable("Type", str);
}
public void setId(String str) {
setRequestVariable("ID", str);
}
public void setFormat(String str) {
setRequestVariable("Format", str);
}
// public void setResource(String str) {
// setRequestVariable("resource", str);
// }
// public void setResourceClass(String str) {
// setRequestVariable("resourceClass", str);
// }
public void setVersion(String version) {
this.version = version;
}
public String getVersion() {
return version;
}
}

View File

@ -0,0 +1,350 @@
package org.realtor.rets.retsapi;
import org.apache.log4j.Category;
import java.io.IOException;
import java.io.InputStream;
import java.util.Iterator;
import java.util.Collection;
import java.util.ArrayList;
import javax.mail.internet.MimeMultipart;
import javax.mail.internet.InternetHeaders;
import javax.mail.internet.MimeBodyPart;
import javax.mail.MessagingException;
/**
* RETSGetObjectTransaction.java
*
* @version 1.0
* @author jbrush
*/
public class RETSGetObjectTransaction extends RETSTransaction
{
/**
* Encapsulates the RETS GetObject transaction, and provides services for
* interpreting the result. As with all {@link RETSTransaction} classes,
* your code should create an instance of this class when it wants to
* perform a GetObject transaction. The transaction requires three
* parameters: the resource name (see {@link #setResource}), the type
* of object requested (e.g., <code>"Photo"</code>; see {@link setType}),
* and the ID of the object -- that is, its associated key such as the
* MLS number or agent number. You may also request that the server
* send back only the location of the resource by calling {@link #setLocation}.
*/
static Category cat = Category.getInstance(RETSGetObjectTransaction.class);
// collection of body parts resulting from the collision of the server response with the MIME parsing code.
// protected Collection fBodyParts;
protected ArrayList parts;
/**
* create new RETSGetObjectTransaction and set RequestType
*/
public RETSGetObjectTransaction() {
super();
setRequestType("GetObject");
}
/**
* Sets the response body for the transaction.
*
* @param body body of the transaction
*/
public void setResponse(String body) {
super.setResponse(body);
setKeyValuePairs(body);
}
/**
* Sets the resource attribute to the string passed in.
*
* @param str resource value
*/
public void setResource(String str) {
cat.debug("set Resource=" + str);
setRequestVariable("Resource", str);
}
/**
* Sets the type attribute to the string passed in.
*
* @param type type attribute value
*/
public void setType(String str) {
cat.debug("set Type=" + str);
setRequestVariable("Type", str);
}
/**
* Sets the ID attribute to the string passed in.
*
* @param str ID of the object
*/
public void setID(String str) {
if ( str != null ) {
cat.debug("set ID=" + str.trim());
setRequestVariable("ID", str.trim());
} else {
cat.debug("set ID=" + str);
}
}
/**
* Sets the location attribute to the string passed in.
*
* @param str location attribute value
*/
public void setLocation(String str) {
cat.debug("set Location=" + str);
setRequestVariable("Location", str);
}
/**
* Sets the response stream. This triggers various actions depending on the
* content-type of the response stream:
* If the content-type is text/plain or text/xml, then assume we have a
* RETS response and parse it accordingly. Note that we'll not have
* anything in the RETS response except error information. (We might
* have no error and nothing else, in which case the only possibility
* is that we made a request with Location=1 and the server has
* responded in kind.) We still make this available, in case there *is*
* something else in the response.
* A content-type of<code> multipart</code>, with any subtype, is interpreted as a
* multipart response. This is parsed to create a list of MIME parts.
* Any other content type is simply made available as a single MIME part.
* This method is called by {@link RETSConnection} to provide access to
* the response from a transaction. You don't normally call this method
* yourself.
*
* @param responseStream The response stream to associate with this transaction.
* @call Rarely.
* @override Rarely. You can override this method if you want to provide
* special processing of a GetObject response stream, but
* it will usually be more convenient to override one
* of the methods that handles particular MIME types.
*/
public void setResponseStream(InputStream responseStream) {
String mimeType;
// String contentType = responseHeaderNamed("content-type");
String contentType = super.getResponseHeader("Content-Type");
cat.debug("====[RETSGetObjectTx] --> " + contentType);
int contentTypeSemicolonIndex =
contentType == null ? -1 : contentType.indexOf(";");
// If there was no Content-Type header, we can't do anything here. Punt to the default handler.
if (contentType == null) {
cat.debug("====[RETSGetObjectTx] : NO CONTENT TYPE");
super.setResponseStream(responseStream);
return;
}
// If the content-type string had parameters, trim them to get just the MIME type.
if (contentTypeSemicolonIndex >= 0)
mimeType = contentType.substring(0, contentTypeSemicolonIndex).trim();
else
mimeType = contentType.trim();
cat.debug("====[RETSGetObjectTx] : mime-type -> " + mimeType);
// If the type is text/xml, then this is probably an error response.
// We need to parse the input stream nondestructively to find out.
if (mimeType.equals("text/xml")) {
handleXMLStream(responseStream, mimeType, contentType);
} else if (mimeType.startsWith("multipart/")) {
// If it's multipart, take it apart and set up appropriate data structures.
cat.debug("====[RETSGetObjectTx] : RECIEVED MULTIPART");
handleMultipartStream(responseStream, mimeType, contentType);
} else {
// Otherwise, since we do have a MIME type, assume that the response *is* object value.
handleStreamWithType(responseStream, mimeType, contentType);
}
}
/**
* Handle an input stream whose advertised MIME type is text/xml.
* This may be a RETS error response or something else; we need to figure
* out exactly what it is. If it is a RETS response, parse it and
* deal with it. If not, handle as for an unknown response.
*
* @param responseStream The response stream containing the XML data.
* @call Only from subclasses.
* @ @override Override to provide your own handling of XML data
* streams.
*/
protected void handleXMLStream(InputStream responseStream, String mimeType, String contentType) {
try {
InputStreamDataSource responseStreamDataSource =
new InputStreamDataSource(responseStream, contentType);
RETSBasicResponseParser basicResponseParser =
new RETSBasicResponseParser(responseStreamDataSource.getInputStream());
if (basicResponseParser.responseIsValid()) {
setResponseStatus(Integer.toString(basicResponseParser.replyCode()));
setResponseStatusText(basicResponseParser.replyText());
} else {
makeSinglePartFromByteStream(responseStreamDataSource.contentAsByteArray(), contentType);
setResponseStatus("0"); // The response is valid in this case, since we got a body that we can provide
}
} catch (Exception e) {
// We really need something better for this.
setResponseStatus("20513");
setResponseStatusText("RETSAPI: Could not create a MIME body part from XML stream: " + e.getMessage());
}
}
/**
* Handle an input stream whose advertised MIME type is <code>multipart</code>.
* This involves breaking up the stream into its constituent parts
* for callers to retrieve.
*
* @param responseStream The stream to parse.
* @param mimeType The MIME type and subtype associated with the stream.
* @param contentType The Content-Type header, including the MIME type and its parameters, if any.
* @call Only from subclasses.
* @override Override to provide your own handling of MIME multipart
* <p/>
* data.
*/
protected void handleMultipartStream(InputStream responseStream, String mimeType, String contentType) {
InputStreamDataSource responseStreamDataSource = null;
try {
responseStreamDataSource = new InputStreamDataSource(responseStream, contentType);
MimeMultipart multipartResponse = new MimeMultipart(responseStreamDataSource);
// multipartResponse.writeTo(System.err);
parts = new ArrayList();
int partCount = multipartResponse.getCount();
for (int i = 0; i < partCount; ++i) {
parts.add(multipartResponse.getBodyPart(i));
}
setResponseStatus("0");
} catch (MessagingException messagingException) {
if (responseStreamDataSource != null)
cat.debug(responseStreamDataSource.bufferedDataAsString());
// System.out.println(responseStreamDataSource.bufferedDataAsString());
messagingException.printStackTrace();
setResponseStatus("20513");
setResponseStatusText("RETSAPI: Could not create a multipart stream from response: " + messagingException.getMessage());
} catch (IOException ioException) {
ioException.printStackTrace();
setResponseStatus("20513");
setResponseStatusText("RETSAPI: I/O exception while creating multipart stream from response: " + ioException.getMessage());
} finally {
// We always want at least an empty body part list.
if ( parts == null ) parts = new ArrayList();
}
}
/**
* Helper for making the response into a single body part. This takes an
* byte array which may have been created during an earlier
* phase of processing, rather than taking an <code>InputStream</code>.
*
* @param inputBytes A byte array containing the response data.
* @param contentType The content-type header.
* @call Rarely.
* @override Rarely.
*/
protected void makeSinglePartFromByteStream(byte[] inputBytes, String contentType) {
// First, we need to gather the response headers into an InternetHeader object
InternetHeaders originalHeaders = new InternetHeaders();
Iterator headerIterator = getResponseHeaderMap().keySet().iterator();
Object headerContent = null;
String headerName = null;
while (headerIterator.hasNext()) {
headerName = (String) headerIterator.next();
// String headerContent = (String) getResponseHeaderMap().get(headerName);
headerContent = getResponseHeaderMap().get(headerName);
if ( headerContent != null )
originalHeaders.addHeader(headerName, headerContent.toString());
}
parts = new ArrayList(1); // We may not have *any*, but we won't have more than 1.
try {
parts.add(new MimeBodyPart(originalHeaders, inputBytes));
setResponseStatus("0");
} catch (Exception e) {
e.printStackTrace();
setResponseStatus("20513");
setResponseStatusText("RETSAPI: Could not create a MIME body part from response: " + e.getMessage());
}
}
/**
* Handle an input stream whose advertised MIME type isn't either
* multipart or XML. This packages up the stream as its own MIME part
* in order to offer it through the normal multipart interface.
*
* @param responseStream The stream to parse.
* @param mimeType The MIME type and subtype associated with the stream.
* @param contentType The Content-Type header, including the MIME type and its parameters, if any.
* @call Only from subclasses.
* @override Override to provide your own handling of data with special
* <p/>
* MIME types.
*/
protected void handleStreamWithType(InputStream responseStream, String mimeType, String contentType) {
try {
makeSinglePartFromByteStream(
(new InputStreamDataSource(responseStream, contentType)).contentAsByteArray(), contentType);
} catch (IOException e) {
e.printStackTrace();
setResponseStatus("20513");
setResponseStatusText("RETSAPI: Could not create a data source from response: " + e.getMessage());
}
}
/**
* Returns the count of retrieved objects.
*/
public int getObjectCount() {
if ( parts == null ) return 0;
return parts.size();
}
/**
* Returns a vector of all objects found. These are stored as MimeBodyPart objects.
* The returned vector may be empty.
*/
public Collection allReturnedObjects() {
return parts;
}
/**
* Returns the object with the given index as a MIME body part. Returns <code>null</code>
* if no object with the given index exists.
*
* @param objectIndex The index of the object to retrieve.
*/
public MimeBodyPart partAtIndex(int objectIndex) {
if ( parts == null || objectIndex < 0 || objectIndex >= parts.size() )
return null;
return (MimeBodyPart) parts.get(objectIndex);
}
public InputStream getPartAsStream(int objectIndex) {
InputStream inputStream = null;
MimeBodyPart part = this.partAtIndex(objectIndex);
try {
if ( part != null ) {
Object content = part.getContent();
inputStream = (InputStream) content;
cat.debug("--- MimeBodyPart Content--> " + content);
}
} catch (Exception e) {
e.printStackTrace();
throw new RuntimeException("Kablewie!");
}
return inputStream;
}
}

View File

@ -0,0 +1,179 @@
package org.realtor.rets.retsapi;
//import org.apache.regexp.*;
import org.apache.log4j.*;
import java.net.*;
import java.util.*;
/**
* RETSLoginTransaction.java
*
*
* @author jbrush
* @version 1.0
*/
public class RETSLoginTransaction extends RETSTransaction {
/** log4j Object */
static Category cat = Category.getInstance(RETSLoginTransaction.class);
/**
* capablitiy list
*/
private static final String[] capList = {
"Login", // Login first because it might reset URL root
"Action", "ChangePassword", "GetObject", "LoginComplete", "Logout",
"Search", "GetMetadata", "Update", "ServerInformation"
};
String url = null;
String version = null;
public RETSLoginTransaction() {
super();
setRequestType("Login");
}
/** Sets the response body. This method is called from RETSConnection.execute()
* @param body body of the response
*/
public void setResponse(String body) {
super.setResponse(body);
setKeyValuePairs(body);
setCapabilityUrls();
}
/** Sets the username for this transaction
* @param username the user's login name
*/
public void setUsername(String username) {
setRequestVariable("username", username);
}
/** sets the User's password for this transaction.
* @param password password string
*/
public void setPassword(String password) {
setRequestVariable("password", password);
}
/** sets the URL for this transaction.
* @param url url string
*/
public void setUrl(String url) {
this.url = url;
}
/** gets the URL for this transaction.
* @param url url string
*/
public String getUrl() {
return url;
}
public void setVersion(String version) {
this.version = version;
}
public String getVersion() {
return version;
}
/**
*
*/
public void preprocess() {
super.preprocess();
// save the username and password
transactionContext.put("username", getRequestVariable("username"));
transactionContext.put("password", getRequestVariable("password"));
}
/** Extracts the capabilitiesUrls out of the response body.
*
*/
void setCapabilityUrls() {
Map respMap = getResponseMap();
Set respKeySet = respMap.keySet();
Iterator iter = null;
String key = null;
int capLength = capList.length;
String urlRoot = getUrlRoot(url); // set root to current url root
String capUrl = null;
String qualifiedUrl = null;
/* jump thru hoop because key might not be in proper mixed-case so we need to map it */
for (int i = 0; i < capLength; i++) {
iter = respKeySet.iterator();
while (iter.hasNext()) {
key = (String) iter.next();
if (capList[i].equalsIgnoreCase(key)) {
capUrl = getResponseVariable(key);
qualifiedUrl = qualifyUrl(capUrl, urlRoot);
cat.debug(capList[i] + "=[" + qualifiedUrl + "]");
putCapabilityUrl(capList[i], qualifiedUrl);
if (capList[i].equalsIgnoreCase("Login")) // login may reset rootUrl
{
urlRoot = getUrlRoot(qualifiedUrl);
}
break;
}
}
}
}
/**
* Makes sure url is fully qualified.
*/
private String qualifyUrl(String url, String defaultRoot) {
String root = getUrlRoot(url);
String sep = "";
if (root == null) {
if (url.charAt(0) != '/') {
sep = "/";
}
return defaultRoot + sep + url;
} else {
return url;
}
}
String getUrlRoot(String myUrl) {
try {
URL url = new URL(myUrl);
String protocol = url.getProtocol();
String host = url.getHost();
int port = url.getPort();
//String path = url.getPath();
//String file = url.getFile();
cat.debug("protocol = [" + protocol + "]");
cat.debug("host = [" + host + "]");
cat.debug("port = [" + port + "]");
//cat.debug("path = ["+path+"]");
//cat.debug("file = ["+file+"]");
return protocol + "://" + host + ((port > 0) ? (":" + port) : "");
} catch (MalformedURLException e) {
cat.warn("getUrlRoot:MalformedURLException myUrl=\"" + myUrl +
"\"");
}
return null;
}
}

View File

@ -0,0 +1,31 @@
package org.realtor.rets.retsapi;
import org.apache.log4j.*;
/**
* Send a logout transaction to the server.
*
* @author jbrush
* @version 1.0
*/
public class RETSLogoutTransaction extends RETSTransaction {
static Category cat = Category.getInstance(RETSLogoutTransaction.class);
/** Create a new RETSLogoutTransaction */
public RETSLogoutTransaction() {
super();
setRequestType("Logout");
}
/** Sets the response body. Called from RETSConnection.execute()
* after the logout transaction is executed.
*
* @param body Body of the response to the RETSLogoutTransaction.
*/
public void setResponse(String body) {
super.setResponse(body);
setKeyValuePairs(body);
}
}

View File

@ -0,0 +1,31 @@
package org.realtor.rets.retsapi;
import org.apache.log4j.*;
/**
* RETSSearchAgentTransaction.java
* Search for agents
*
* @author jbrush
* @version 1.0
*/
public class RETSSearchAgentTransaction extends RETSSearchTransaction {
static Category cat = Category.getInstance(RETSSearchAgentTransaction.class);
/**create a new RETSSearchAgentTransaction*/
public RETSSearchAgentTransaction() {
super();
setSearchType("Agent");
setSearchClass("Agent");
}
/** Search by last name, pass in the lastname of a user
* as the "query" argument.
* @param searchByLastName lastname of the user to search.
*/
public void setSearchByLastname(String searchByLastname) {
// convert to DMQL
setSearchQuery("(LastName=" + searchByLastname + ")");
}
}

View File

@ -0,0 +1,26 @@
package org.realtor.rets.retsapi;
import org.apache.log4j.*;
/**
* RETSSearchOfficeTransaction.java
* Performs a getOffice Transaction
*
* @author jbrush
* @version 1.0
*/
public class RETSSearchOfficeTransaction extends RETSSearchTransaction {
static Category cat = Category.getInstance(RETSSearchOfficeTransaction.class);
/** Creates new a RETSSearchOfficeTransaction
*
*/
public RETSSearchOfficeTransaction() {
super();
setSearchType("Office");
setSearchClass("Office");
// setSearchClass("OFF");
}
}

View File

@ -0,0 +1,25 @@
package org.realtor.rets.retsapi;
import org.apache.log4j.*;
/**
* RETSSearchPropertyBatchTransaction.java
*
* @author jbrush
* @version 1.0
*/
public class RETSSearchPropertyBatchTransaction extends RETSSearchTransaction {
static Category cat = Category.getInstance(RETSSearchPropertyBatchTransaction.class);
public RETSSearchPropertyBatchTransaction() {
super();
setSearchType("Property");
setSearchClass("RES");
}
public void setSearchByListingAgent(String agent) {
// convert to DMQL
setSearchQuery("(AgentID=" + agent + ")");
}
}

View File

@ -0,0 +1,19 @@
package org.realtor.rets.retsapi;
import org.apache.log4j.*;
/**
* RETSSearchPropertyBatchTransaction.java
*
* @author jbrush
* @version 1.0
*/
public class RETSSearchPropertyTransaction extends RETSSearchTransaction {
static Category cat = Category.getInstance(RETSSearchPropertyTransaction.class);
public RETSSearchPropertyTransaction() {
super();
setSearchType("Property");
}
}

View File

@ -0,0 +1,326 @@
package org.realtor.rets.retsapi;
import org.apache.log4j.Category;
import org.realtor.rets.util.AttributeExtracter;
import org.realtor.rets.util.ResourceLocator;
import org.xml.sax.helpers.DefaultHandler;
import java.io.ByteArrayInputStream;
import java.util.HashMap;
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;
/**
* RETSSearchTransaction.java
*
* @author jbrush
* @version 1.0
*/
public class RETSSearchTransaction extends RETSTransaction {
static Category cat = Category.getInstance(RETSSearchTransaction.class);
//Required Arguments
protected static final String SEARCHTYPE = "SearchType";
protected static final String SEARCHCLASS = "Class";
protected static final String SEARCHQUERY = "Query";
protected static final String SEARCHQUERYTYPE = "QueryType";
// Optional Arguments
protected static final String SEARCHCOUNT = "Count";
protected static final String SEARCHFORMAT = "Format";
protected static final String SEARCHLIMIT = "Limit";
protected static final String SEARCHOFFSET = "Offset";
protected static final String SEARCHSELECT = "Select";
protected static final String SEARCHDELIMITER = "DELIMITER";
protected static final String SEARCHRESTRICTEDINDICATOR = "RestrictedIndicator";
protected static final String SEARCHSTANDARDNAMES = "StandardNames";
private String version = null;
public RETSSearchTransaction() {
super();
setRequestType("Search");
setSearchQueryType("DMQL");
}
public void setResponse(String body) {
super.setResponse(body);
HashMap hm = this.getAttributeHash(body);
processXML(hm);
}
///////////////////////////////////////////////////////////////////////
/* void processCompact(String body) {
processCountTag(body);
processDelimiterTag(body);
processColumnTag(body);
processCompactData(body);
processMaxRowTag(body);
} */
void processXML(HashMap hash) {
if (hash == null) {
return;
}
processCountTag((HashMap) hash.get("COUNT"));
processXMLData((HashMap) hash.get("BODY"));
processMaxRowTag((HashMap) hash.get("MAXROWS"));
processDelimiterTag((HashMap) hash.get("DELIMITER"));
}
private HashMap getAttributeHash(String body) {
AttributeExtracter ae = new AttributeExtracter();
DefaultHandler h = ae;
try {
SAXParserFactory spf = SAXParserFactory.newInstance();
SAXParser p = spf.newSAXParser();
ByteArrayInputStream bais = new ByteArrayInputStream(body.getBytes());
p.parse(bais, h, "file:/" + ResourceLocator.locate("dummy.dtd"));
} catch (Exception e) {
cat.warn(e, e);
return null;
}
return ae.getHash();
}
void processCountTag(HashMap hash) {
if (hash == null) {
return;
}
String records = (String) hash.get("Records");
if ( records == null) {
records = (String) hash.get("records");
}
if ( records == null) {
records = (String) hash.get("RECORDS");
}
setCount( records);
}
void processDelimiterTag(HashMap hash) {
if (hash == null) {
return;
}
String delim = (String) hash.get("value");
if (delim == null) {
delim = (String) hash.get("VALUE");
}
if (delim == null) {
delim = (String) hash.get("Value");
}
setSearchDelimiter(delim);
}
void processColumnTag(HashMap hash) {
}
void processCompactData(HashMap hash) {
}
void processXMLData(HashMap hash) {
}
void processMaxRowTag(HashMap hash) {
if (hash == null) {
setResponseVariable("MAXROWS", "true");
}
// else
// setResponseVariable("MAXROWS", "false");
}
///////////////////////////////////////////////////////////////////////
public void setSearchType(String searchType) {
setRequestVariable(SEARCHTYPE, searchType);
}
public String getSearchType() {
return getRequestVariable(SEARCHTYPE);
}
///////////////////////////////////////////////////////////////////////
public void setSearchClass(String searchClass) {
setRequestVariable(SEARCHCLASS, searchClass);
}
public String getSearchClass() {
return getRequestVariable(SEARCHCLASS);
}
///////////////////////////////////////////////////////////////////////
public void setSearchQuery(String searchQuery) {
setRequestVariable(SEARCHQUERY, searchQuery);
}
public String getSearchQuery() {
return getRequestVariable(SEARCHQUERY);
}
public void setQuery(String searchQuery) {
setRequestVariable(SEARCHQUERY, searchQuery);
}
public String getQuery() {
return getRequestVariable(SEARCHQUERY);
}
///////////////////////////////////////////////////////////////////////
public void setSearchQueryType(String searchQueryType) {
setRequestVariable(SEARCHQUERYTYPE, searchQueryType);
}
public String getSearchQueryType() {
return getRequestVariable(SEARCHQUERYTYPE);
}
public void setQueryType(String searchQueryType) {
setRequestVariable(SEARCHQUERYTYPE, searchQueryType);
}
public String getQueryType() {
return getRequestVariable(SEARCHQUERYTYPE);
}
///////////////////////////////////////////////////////////////////////
public void setSearchCount(String value) {
setRequestVariable(SEARCHCOUNT, value);
}
public String getSearchCount() {
return getRequestVariable(SEARCHCOUNT);
}
public void setCount(String value) {
setRequestVariable(SEARCHCOUNT, value);
}
public String getCount() {
return getRequestVariable(SEARCHCOUNT);
}
///////////////////////////////////////////////////////////////////////
public void setSearchFormat(String value) {
setRequestVariable(SEARCHFORMAT, value);
}
public String getSearchFormat() {
return getRequestVariable(SEARCHFORMAT);
}
public void setFormat(String value) {
setRequestVariable(SEARCHFORMAT, value);
}
public String getFormat() {
return getRequestVariable(SEARCHFORMAT);
}
///////////////////////////////////////////////////////////////////////
public void setSearchLimit(String value) {
setRequestVariable(SEARCHLIMIT, value);
}
public String getSearchLimit() {
return getRequestVariable(SEARCHLIMIT);
}
public void setLimit(String value) {
setRequestVariable(SEARCHLIMIT, value);
}
public String getLimit() {
return getRequestVariable(SEARCHLIMIT);
}
///////////////////////////////////////////////////////////////////////
public void setSearchOffset(String value) {
setRequestVariable(SEARCHOFFSET, value);
}
public String getSearchOffset() {
return getRequestVariable(SEARCHOFFSET);
}
public void setOffset(String value) {
setRequestVariable(SEARCHOFFSET, value);
}
public String getOffset() {
return getRequestVariable(SEARCHOFFSET);
}
///////////////////////////////////////////////////////////////////////
public void setSearchSelect(String value) {
setRequestVariable(SEARCHSELECT, value);
}
public String getSearchSelect() {
return getRequestVariable(SEARCHSELECT);
}
public void setSelect(String value) {
setRequestVariable(SEARCHSELECT, value);
}
public String getSelect() {
return getRequestVariable(SEARCHSELECT);
}
///////////////////////////////////////////////////////////////////////
public void setSearchDelimiter(String value) {
setRequestVariable(SEARCHDELIMITER, value);
}
public String getSearchDelimiter() {
return getRequestVariable(SEARCHDELIMITER);
}
///////////////////////////////////////////////////////////////////////
public void setSearchRestrictedIndicator(String value) {
setRequestVariable(SEARCHRESTRICTEDINDICATOR, value);
}
public String getSearchRestrictedIndicator() {
return getRequestVariable(SEARCHRESTRICTEDINDICATOR);
}
///////////////////////////////////////////////////////////////////////
public void setSearchStandardNames(String value) {
setRequestVariable(SEARCHSTANDARDNAMES, value);
}
public String getSearchStandardNames() {
return getRequestVariable(SEARCHSTANDARDNAMES);
}
public void setStandardNames(String value) {
setRequestVariable(SEARCHSTANDARDNAMES, value);
}
public String getStandardNames() {
return getRequestVariable(SEARCHSTANDARDNAMES);
}
public void setVersion(String version) {
this.version = version;
}
public String getVersion() {
return version;
}
}

View File

@ -0,0 +1,48 @@
/**
* RETSServerInformationTransaction.java
*
* @author pobrien
* @version
*/
package org.realtor.rets.retsapi;
//import java.util.*;
import org.apache.log4j.*;
///////////////////////////////////////////////////////////////////////
public class RETSServerInformationTransaction extends RETSTransaction {
static Category cat = Category.getInstance(RETSServerInformationTransaction.class);
String version = null;
/**
* constructor
*/
public RETSServerInformationTransaction() {
super();
setRequestType("ServerInformation");
}
public void setResource(String str) {
setRequestVariable("Resource", str);
}
public void setInfoClass(String str) {
setRequestVariable("Class", str);
}
public void setStandardNames(String str) {
setRequestVariable("StandardNames", str);
}
public void setVersion(String version) {
this.version = version;
}
public String getVersion() {
return version;
}
}

View File

@ -0,0 +1,274 @@
/**
* RETSTransaction.java
*
* @author jbrush
* @version
*/
package org.realtor.rets.retsapi;
import org.apache.log4j.*;
import org.apache.regexp.*;
import org.realtor.rets.util.*;
import java.io.*;
import java.util.*;
///////////////////////////////////////////////////////////////////////
public class RETSTransaction extends RETSRequestResponse {
static Category cat = Category.getInstance(RETSTransaction.class);
private static final String STATUS = "status";
private static final String STATUSTEXT = "statusText";
private static final String BODY = "body";
private static final String REQUESTTYPE = "requestType";
protected static final String RESOURCE = "Resource";
protected static final String CLASS_NAME = "ClassName";
protected HashMap transactionContext = null;
private HashMap capabilityUrls = null;
protected HashMap responseHeaderMap = null;
InputStream responseStream = null;
RE firstStatusRE = null;
RE secondStatusRE = null;
/**
* Holds value of property compressionFormat.
*/
private String compressionFormat = null;
public RETSTransaction() {
super();
try {
// TODO: RE's should be precompiled
firstStatusRE = new RE("<RETS\\s?ReplyCode=\"(.*?)\"\\s?ReplyText=\"(.*?)\"");
secondStatusRE = new RE("<RETS-STATUS\\s?ReplyCode=\"(.*?)\"\\s?ReplyText=\"(.*?)\"");
} catch (RESyntaxException e) {
cat.error("Error compiling REs", e);
}
}
public void setResource(String resource) {
setRequestVariable(RESOURCE, resource);
}
public String getResource() {
return getRequestVariable(RESOURCE);
}
public void setClassName(String className) {
setRequestVariable(CLASS_NAME, className);
}
public String getClassName() {
return getRequestVariable(CLASS_NAME);
}
///////////////////////////////////////////////////////////////////////
public void setRequestType(String type) {
setRequestVariable(REQUESTTYPE, type);
}
public String getRequestType() {
return getRequestVariable(REQUESTTYPE);
}
///////////////////////////////////////////////////////////////////////
public void setRequest(String body) {
setRequestVariable(BODY, body);
}
public String getRequest() {
return getRequestVariable(BODY);
}
///////////////////////////////////////////////////////////////////////
public void setResponse(String body) {
setResponseVariable(BODY, body);
// extract values
// cat.debug("looking for <RETS tag");
if ((body == null) || !firstStatusRE.match(body)) {
return;
}
setResponseStatus(firstStatusRE.getParen(1));
setResponseStatusText(firstStatusRE.getParen(2));
// extract RETS-STATUS values is any
if (secondStatusRE.match(body)) {
setResponseStatus(secondStatusRE.getParen(1));
setResponseStatusText(secondStatusRE.getParen(2));
}
}
public String getResponse() {
return getResponseVariable(BODY);
}
///////////////////////////////////////////////////////////////////////
public void setResponseStream(InputStream is) {
responseStream = is;
}
public InputStream getResponseStream() {
return responseStream;
}
///////////////////////////////////////////////////////////////////////
public void setResponseStatus(String status) {
setResponseVariable(STATUS, status);
}
public String getResponseStatus() {
return getResponseVariable(STATUS);
}
///////////////////////////////////////////////////////////////////////
public void setResponseStatusText(String statusText) {
setResponseVariable(STATUSTEXT, statusText);
}
public String getResponseStatusText() {
return getResponseVariable(STATUSTEXT);
}
///////////////////////////////////////////////////////////////////////
public String getUrl() {
String url = getCapabilityUrl(getRequestType());
cat.debug("getUrl():" + getRequestType() + " url:" + url);
return url;
}
///////////////////////////////////////////////////////////////////////
void setKeyValuePairs(String str) {
if (str == null) {
return;
}
StringTokenizer lineTokenizer = new StringTokenizer(str, "\r\n");
while (lineTokenizer.hasMoreTokens()) {
String line = lineTokenizer.nextToken();
// if tag, ignore it
if (line.charAt(0) != '<') {
int equalSign = line.indexOf("=");
if (equalSign >= 0) {
setResponseVariable(line.substring(0, equalSign).trim(),
line.substring(equalSign + 1).trim());
}
}
}
}
///////////////////////////////////////////////////////////////////////
void putCapabilityUrl(String key, String value) {
if (capabilityUrls == null) {
capabilityUrls = new HashMap();
}
capabilityUrls.put(key, value);
}
public String getCapabilityUrl(String key) {
return (String) capabilityUrls.get(key);
}
///////////////////////////////////////////////////////////////////////
public void preprocess() {
// by default does nothing
//subclasses can override
}
public void postprocess() {
// by default does nothing
//subclasses can override
}
void setContext(HashMap transactionContext) {
if (transactionContext != null) {
this.transactionContext = transactionContext;
capabilityUrls = (HashMap) transactionContext.get("capabilityUrls");
if (capabilityUrls == null) {
capabilityUrls = new HashMap();
transactionContext.put("capabilityUrls", capabilityUrls);
}
}
}
public HashMap getTransactionContext() {
return transactionContext;
}
public HashMap getResponseHeaderMap() {
return responseHeaderMap;
}
public void setResponseHeaderMap(HashMap responseHeaders) {
responseHeaderMap = responseHeaders;
}
/**
* Returns the value of the response header with the specified name, or <code>null</code>
* if the header was not returned.
*
* @param headerName The name of the header to be retrieved.
*/
public String getResponseHeader(String headerName) {
String responseString = null;
// If we have no header map, we obviously have no headers. Also, if
// there is no list for the header name, we don't have the
// requested header.
if ( headerName != null && headerName.equals("content-type") ) {
headerName = "Content-Type";
}
if (responseHeaderMap != null) {
cat.debug("RESPONSEHEADERMAP ==> " + responseHeaderMap.toString());
// responseString = (String) responseHeaderMap.get(headerName.toLowerCase());
cat.debug("ContentType Class is ... " + responseHeaderMap.get(headerName).getClass().getName());
Object object = responseHeaderMap.get(headerName);
if ( object == null )
return null;
if ( object instanceof ArrayList ) {
responseString = (String) ((ArrayList)object).get(0);
} else
responseString = object.toString();
} else {
cat.debug("RESPONSEHEADERMAP ==> " + responseHeaderMap);
}
return responseString;
}
/**
* Getter for property compressionFormat.
*
* @return Value of property compressionFormat.
*/
public String getCompressionFormat() {
return this.compressionFormat;
}
/**
* Setter for property compressionFormat.
*
* @param compressionFormat New value of property compressionFormat.
*/
public void setCompressionFormat(String compressionFormat) {
this.compressionFormat = compressionFormat;
}
static public void log(String logMessage) {
cat.debug(logMessage);
}
}

View File

@ -0,0 +1,166 @@
package org.realtor.rets.retsapi;
import org.apache.log4j.Category;
import java.util.Iterator;
import java.util.Map;
import org.apache.xpath.XPathAPI;
import org.realtor.rets.util.XMLUtils;
import org.w3c.dom.Document;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;
import java.util.Collections;
import java.util.Vector;
import javax.xml.transform.TransformerException;
/**
* RETSUpdateTransaction.java
*
* @author pobrien
* @version 1.0
*/
public class RETSUpdateTransaction extends RETSTransaction {
static Category cat = Category.getInstance(RETSUpdateTransaction.class);
/**
*
*/
public RETSUpdateTransaction() {
super();
setRequestType("Update");
setDelimiter("09");//default is ascii ht
}
/**
* Sets the response body for the transaction.
*
* @param body body of the transaction
*/
public void setResponse(String body) {
super.setResponse(body);
System.out.println("Setting response as " + body);
setKeyValuePairs(body);
}
/**
* Sets the type attribute to the string passed in.
*
* @param type type attribute value
*/
public void setType(String str) {
cat.debug("set Type=" + str);
setRequestVariable("Type", str);
}
/**
* Sets the ID attribute to the string passed in.
*
* @param str ID of the object
*/
public void setValidate(String str) {
cat.debug("set Validate=" + str);
setRequestVariable("Validate", str);
}
/**
* Sets the location attribute to the string passed in.
*
* @param str location attribute value
*/
public void setDelimiter(String str) {
cat.debug("set Delimiter=" + str);
setRequestVariable("Delimiter", str);
}
public String getDelimiter() {
return getRequestVariable("Delimiter");
}
public void setRecord(String str) {
cat.debug("set Record=" + str);
setRequestVariable("Record", str);
}
public void setWarningResponse(String str) {
cat.debug("set WarningResponse=" + str);
setRequestVariable("WarningResponse", str);
}
public void setNewValues(Map m) {
// convert to a string and feed to setRecord()....
StringBuffer record = new StringBuffer();
Iterator iter = m.keySet().iterator();
// delimiter is a 2 digit HEX value
char delim = (char) Integer.parseInt(getDelimiter().trim(), 16);
while (iter.hasNext()) {
String name = (String) iter.next();
Object val = m.get(name);
String value = "";
if (val instanceof String) {
value = (String) val;
} else {
String[] arr = (String[]) val;
value = arr[0];
}
record.append(name);
record.append("=");
record.append(value);
if (iter.hasNext()) {
record.append(delim);
}
}
setRecord(record.toString());
}
public void setWarningResponseValues(Map m) {
// convert to a string and feed to setWarningResponse()....
StringBuffer warning = new StringBuffer("(");
Iterator iter = m.keySet().iterator();
// delimiter is a 2 digit HEX value
char delim = (char) Integer.parseInt(getDelimiter().trim(), 16);
while (iter.hasNext()) {
String name = (String) iter.next();
Object val = m.get(name);
String value = "";
if (val instanceof String) {
value = (String) val;
} else {
String[] arr = (String[]) val;
value = arr[0];
}
warning.append(name);
warning.append("=");
warning.append(value);
if (iter.hasNext()) {
warning.append(delim);
}
}
warning.append(")");
setWarningResponse(warning.toString());
}
public void setUID(String id) {
System.out.println("UID is " + id);
setRequestVariable("OriginalUid", id);
}
}