USRE-88 Push new file for example

This commit is contained in:
YuCheng Hu 2021-11-30 13:30:11 -05:00
parent 4d8d8fbee7
commit 42e924952d
198 changed files with 16789 additions and 0 deletions

266
rets-io-client/pom.xml Normal file
View File

@ -0,0 +1,266 @@
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.ossez.usreio</groupId>
<artifactId>rets-io-client</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>jar</packaging>
<parent>
<groupId>com.ossez.usreio</groupId>
<artifactId>rets-io</artifactId>
<version>0.0.1-SNAPSHOT</version>
</parent>
<name>Rets-Io-Client</name>
<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>https://github.com/USRealEstate/rets-io.git</url>
<developers>
<developer>
<name>YuCheng Hu</name>
<id>honeymoose</id>
<email>huyuchengus@gmail.com</email>
<timezone>-5</timezone>
<organization>Open Source</organization>
<roles>
<role>Sr. Java Developer</role>
</roles>
</developer>
</developers>
<profiles>
<profile>
<id>local</id>
<properties>
<env>local</env>
<client.local.directory>/tmp/files</client.local.directory>
</properties>
<activation>
<activeByDefault>true</activeByDefault>
</activation>
</profile>
</profiles>
<dependencies>
<dependency>
<groupId>com.ossez.usreio</groupId>
<artifactId>rets-io-common</artifactId>
<version>0.0.1-SNAPSHOT</version>
</dependency>
<!-- LOG -->
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>${logback.version}</version>
</dependency>
<!-- APACHE COMMONS -->
<dependency>
<groupId>commons-httpclient</groupId>
<artifactId>commons-httpclient</artifactId>
<version>3.1</version>
</dependency>
<dependency>
<groupId>org.apache.ant</groupId>
<artifactId>ant</artifactId>
<version>1.10.11</version>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>3.9</version>
</dependency>
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
<version>4.5.13</version>
</dependency>
<dependency>
<groupId>org.dom4j</groupId>
<artifactId>dom4j</artifactId>
<version>2.1.1</version>
</dependency>
<dependency>
<groupId>xalan</groupId>
<artifactId>xalan</artifactId>
<version>2.7.2</version>
</dependency>
<dependency>
<groupId>javax.activation</groupId>
<artifactId>javax.activation-api</artifactId>
<version>1.2.0</version>
</dependency>
<dependency>
<groupId>javax.mail</groupId>
<artifactId>mail</artifactId>
<version>1.4</version>
</dependency>
<!-- TEST -->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-api</artifactId>
<version>5.7.0</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-engine</artifactId>
<version>5.7.0</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>commons-codec</groupId>
<artifactId>commons-codec</artifactId>
<version>1.3</version>
</dependency>
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>28.1-jre</version>
</dependency>
</dependencies>
<build>
<defaultGoal>package</defaultGoal>
<resources>
<resource>
<directory>src/main/java</directory>
<filtering>true</filtering>
<targetPath>../filtered-sources/java</targetPath>
</resource>
<resource>
<directory>src/main/resources</directory>
<filtering>true</filtering>
</resource>
</resources>
<plugins>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.1</version>
<configuration>
<source>${java.version}</source>
<target>${java.version}</target>
</configuration>
</plugin>
<plugin>
<artifactId>maven-assembly-plugin</artifactId>
<executions>
<execution>
<id>all-jobs</id>
<phase>package</phase>
<goals>
<goal>single</goal>
</goals>
<configuration>
<finalName>trulia-java-rets-client-${env}</finalName>
<descriptorRefs>
<descriptorRef>jar-with-dependencies</descriptorRef>
</descriptorRefs>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>${maven-compiler-plugin.version}</version>
<configuration>
<source>${java.version}</source>
<target>${java.version}</target>
<release>${java.version}</release>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-javadoc-plugin</artifactId>
<version>2.9.1</version>
<executions>
<execution>
<id>attach-javadocs</id>
<goals>
<goal>jar</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
<properties>
<!-- Generic properties -->
<java.version>11</java.version>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<!-- Logging -->
<slf4j.version>1.7.30</slf4j.version>
<log4j.version>1.2.17</log4j.version>
<log4j2.version>2.2</log4j2.version>
<logback.version>1.2.5</logback.version>
<!-- APACHE COMMONS-->
<commons-io.version>2.11.0</commons-io.version>
<commons-lang.version>2.6</commons-lang.version>
<commons-lang3.version>3.11</commons-lang3.version>
<commons-cli.version>1.4</commons-cli.version>
<commons-httpclient.version>4.5.13</commons-httpclient.version>
<!-- UTILS -->
<guava.version>30.1.1-jre</guava.version>
<!-- Hibernate / JPA -->
<hibernate.version>4.3.5.Final</hibernate.version>
<!-- Bean validation -->
<hibernate-validator.version>4.3.1.Final</hibernate-validator.version>
<!-- Database access -->
<tomcat-jdbc.version>7.0.42</tomcat-jdbc.version>
<ehcache.version>2.6.8</ehcache.version>
<hsqldb.version>2.3.2</hsqldb.version>
<!-- DATA STRUCTURES -->
<jackson.version>2.12.4</jackson.version>
<!-- Test -->
<hamcrest.version>2.2</hamcrest.version>
<hamcrest-all.version>1.3</hamcrest-all.version>
<!-- CDN & CLOUD -->
<jclouds.version>1.9.0</jclouds.version>
<modelmapper.version>2.4.4</modelmapper.version>
<lombok.version>1.18.20</lombok.version>
<moneta.version>1.3</moneta.version>
<jmh-core.version>1.33</jmh-core.version>
<exec-maven-plugin.version>3.0.0</exec-maven-plugin.version>
<maven-surefire-plugin.version>2.21.0</maven-surefire-plugin.version>
<maven-compiler-plugin.version>3.8.1</maven-compiler-plugin.version>
<maven-war-plugin.version>3.0.0</maven-war-plugin.version>
</properties>
</project>

View File

@ -0,0 +1,30 @@
/*
* cart: CRT's Awesome RETS Tool
*
* Author: David Terrell
* Copyright (c) 2003, The National Association of REALTORS
* Distributed under a BSD-style license. See LICENSE.TXT for details.
*/
package com.ossez.usreio.client;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
/**
* dbt is lame and hasn't overridden the default
* javadoc string.
*/
public class BrokerCodeRequredException extends RetsException {
private final List mCodeList;
public BrokerCodeRequredException(Collection codes) {
this.mCodeList = Collections.unmodifiableList(new ArrayList(codes));
}
public List getCodeList(){
return this.mCodeList;
}
}

View File

@ -0,0 +1,161 @@
package com.ossez.usreio.client;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.HashMap;
import java.util.Map;
/**
*
*/
public class CapabilityUrls {
private final static Logger logger = LoggerFactory.getLogger(CapabilityUrls.class);
public static final String ACTION_URL = "Action";
public static final String CHANGE_PASSWORD_URL = "ChangePassword";
public static final String GET_OBJECT_URL = "GetObject";
public static final String LOGIN_URL = "Login";
public static final String LOGIN_COMPLETE_URL = "LoginComplete";
public static final String LOGOUT_URL = "Logout";
public static final String SEARCH_URL = "Search";
public static final String GET_METADATA_URL = "GetMetadata";
public static final String UPDATE_URL = "Update";
public static final String SERVER_INFO_URL = "ServerInformation";// for rets 1.7
private final Map mCapabilityUrls;
private URL mUrl;
public CapabilityUrls() {
this(null);
}
public CapabilityUrls(URL baseurl) {
this.mUrl = baseurl;
this.mCapabilityUrls = new HashMap();
}
public void setCapabilityUrl(String capability, String url) {
if (this.mUrl != null) {
try {
String newurl = new URL(this.mUrl, url).toString();
if (!newurl.equals(url)) {
logger.info("qualified " + capability + " URL different: "
+ url + " -> " + newurl);
url = newurl;
}
} catch (MalformedURLException e) {
logger.warn("Couldn't normalize URL", e);
}
}
this.mCapabilityUrls.put(capability, url);
}
public String getCapabilityUrl(String capability) {
return (String) this.mCapabilityUrls.get(capability);
}
public void setActionUrl(String url) {
setCapabilityUrl(ACTION_URL, url);
}
public String getActionUrl() {
return getCapabilityUrl(ACTION_URL);
}
public void setChangePasswordUrl(String url) {
setCapabilityUrl(CHANGE_PASSWORD_URL, url);
}
public String getChangePasswordUrl() {
return getCapabilityUrl(CHANGE_PASSWORD_URL);
}
public void setGetObjectUrl(String url) {
setCapabilityUrl(GET_OBJECT_URL, url);
}
public String getGetObjectUrl() {
return getCapabilityUrl(GET_OBJECT_URL);
}
/**
*
* @param url
*/
public void setLoginUrl(String url) {
if (this.mUrl == null) {
try {
this.mUrl = new URL(url);
} catch (MalformedURLException e) {
logger.debug("java.net.URL can't parse login url: " + url);
this.mUrl = null;
}
}
setCapabilityUrl(LOGIN_URL, url);
}
public String getLoginUrl() {
return getCapabilityUrl(LOGIN_URL);
}
public void setLoginCompleteUrl(String url) {
setCapabilityUrl(LOGIN_COMPLETE_URL, url);
}
public String getLoginCompleteUrl() {
return getCapabilityUrl(LOGIN_COMPLETE_URL);
}
public void setLogoutUrl(String url) {
setCapabilityUrl(LOGOUT_URL, url);
}
public String getLogoutUrl() {
return getCapabilityUrl(LOGOUT_URL);
}
public void setSearchUrl(String url) {
setCapabilityUrl(SEARCH_URL, url);
}
public String getSearchUrl() {
return getCapabilityUrl(SEARCH_URL);
}
public void setGetMetadataUrl(String url) {
setCapabilityUrl(GET_METADATA_URL, url);
}
public String getGetMetadataUrl() {
return getCapabilityUrl(GET_METADATA_URL);
}
public void setUpdateUrl(String url) {
setCapabilityUrl(UPDATE_URL, url);
}
public String getUpdateUrl() {
return getCapabilityUrl(UPDATE_URL);
}
/**
* This is for RETS 1.7 and later and will return an empty string if it is not implemented.
* @param url
*/
public void setServerInfo(String url) {
setCapabilityUrl(SERVER_INFO_URL, url);
}
/**
* This is for RETS 1.7 and later and will return an empty string if it is not implemented.
* @return
*/
public String getServerInfo() {
return getCapabilityUrl(SERVER_INFO_URL);
}
}

View File

@ -0,0 +1,40 @@
package com.ossez.usreio.client;
import java.security.GeneralSecurityException;
import java.security.MessageDigest;
import javax.crypto.Cipher;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.DESKeySpec;
import org.apache.commons.codec.binary.Base64;
public class ChangePasswordRequest extends VersionInsensitiveRequest {
public ChangePasswordRequest(String username, String oldPassword, String newPassword) throws RetsException {
try {
MessageDigest md5 = MessageDigest.getInstance("MD5");
md5.update(username.toUpperCase().getBytes());
md5.update(oldPassword.toUpperCase().getBytes());
byte[] digest = md5.digest();
DESKeySpec keyspec = new DESKeySpec(digest);
SecretKey key = SecretKeyFactory.getInstance("DES").generateSecret(keyspec);
Cipher cipher = Cipher.getInstance("DES/ECB/PKCS5Padding");
cipher.init(Cipher.ENCRYPT_MODE, key);
cipher.update(newPassword.getBytes());
cipher.update(":".getBytes());
cipher.update(username.getBytes());
md5.reset();
md5.update(cipher.doFinal());
byte[] output = md5.digest();
byte[] param = Base64.encodeBase64(output);
setQueryParameter("PWD", new String(param));
} catch (GeneralSecurityException e) {
throw new RetsException(e);
}
}
@Override
public void setUrl(CapabilityUrls urls) {
this.setUrl(urls.getChangePasswordUrl());
}
}

View File

@ -0,0 +1,36 @@
package com.ossez.usreio.client;
import org.dom4j.Document;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;
import java.io.InputStream;
/**
* dbt is lame and hasn't overridden the default
* javadoc string.
*/
public class ChangePasswordResponse {
public ChangePasswordResponse(InputStream stream) throws RetsException {
SAXReader builder = new SAXReader();
Document document = null;
try {
document = builder.read(stream);
} catch (Exception e) {
throw new RetsException(e);
}
Element rets = document.getRootElement();
if (!rets.getName().equals("RETS")) {
throw new RetsException("Invalid Change Password Response");
}
int replyCode = Integer.parseInt(rets.attributeValue("ReplyCode"));
if (replyCode != 0) {
InvalidReplyCodeException exception;
exception = new InvalidReplyCodeException(replyCode);
exception.setRemoteMessage(rets.attributeValue("ReplyText"));
throw exception;
}
}
}

View File

@ -0,0 +1,40 @@
package com.ossez.usreio.client;
import java.util.Collection;
import java.util.Iterator;
import java.util.NoSuchElementException;
public class CollectionOfCollectionsIterator implements Iterator {
private Iterator mOuter;
private Iterator mInner;
public CollectionOfCollectionsIterator(Collection c) {
this.mOuter = c.iterator();
hasNext();
}
public boolean hasNext() {
if( this.mInner != null && this.mInner.hasNext() ) {
return true;
}
while( this.mOuter.hasNext() ){
this.mInner = ((Collection) this.mOuter.next()).iterator();
if( this.mInner.hasNext() ){
return true;
}
}
return false;
}
public Object next() {
if ( this.hasNext() )
return this.mInner.next();
throw new NoSuchElementException();
}
public void remove() throws UnsupportedOperationException {
throw new UnsupportedOperationException();
}
}

View File

@ -0,0 +1,180 @@
package com.ossez.usreio.client;
import java.io.UnsupportedEncodingException;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import com.ossez.usreio.common.util.CaseInsensitiveTreeMap;
import org.apache.commons.codec.digest.DigestUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.http.Header;
import org.apache.http.HttpResponse;
import org.apache.http.HttpStatus;
import org.apache.http.StatusLine;
import org.apache.http.auth.AuthScope;
import org.apache.http.auth.UsernamePasswordCredentials;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.methods.HttpRequestBase;
import org.apache.http.client.params.ClientPNames;
import org.apache.http.client.params.CookiePolicy;
import org.apache.http.cookie.Cookie;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.impl.conn.tsccm.ThreadSafeClientConnManager;
import org.apache.http.params.BasicHttpParams;
import org.apache.http.params.HttpConnectionParams;
public class CommonsHttpClient extends RetsHttpClient {
private static final int DEFAULT_TIMEOUT = 300000;
private static final String RETS_VERSION = "RETS-Version";
private static final String RETS_SESSION_ID = "RETS-Session-ID";
private static final String RETS_REQUEST_ID = "RETS-Request-ID";
private static final String USER_AGENT = "User-Agent";
private static final String RETS_UA_AUTH_HEADER = "RETS-UA-Authorization";
private static final String ACCEPT_ENCODING = "Accept-Encoding";
public static final String CONTENT_ENCODING = "Content-Encoding";
public static final String DEFLATE_ENCODINGS = "gzip,deflate";
public static final String CONTENT_TYPE = "Content-Type";
public static BasicHttpParams defaultParams(int timeout) {
BasicHttpParams httpClientParams = new BasicHttpParams();
// connection to server timeouts
HttpConnectionParams.setConnectionTimeout(httpClientParams, timeout);
HttpConnectionParams.setSoTimeout(httpClientParams, timeout);
// set to rfc 2109 as it puts the ASP (IIS) cookie _FIRST_, this is critical for interealty
httpClientParams.setParameter(ClientPNames.COOKIE_POLICY, CookiePolicy.RFC_2109);
return httpClientParams;
}
public static ThreadSafeClientConnManager defaultConnectionManager(int maxConnectionsPerRoute, int maxConnectionsTotal) {
// allows for multi threaded requests from a single client
ThreadSafeClientConnManager connectionManager = new ThreadSafeClientConnManager();
connectionManager.setDefaultMaxPerRoute(maxConnectionsPerRoute);
connectionManager.setMaxTotal(maxConnectionsTotal);
return connectionManager;
}
private final ConcurrentHashMap<String, String> defaultHeaders;
private final DefaultHttpClient httpClient;
// method choice improvement
private final String userAgentPassword;
public CommonsHttpClient() {
this(new DefaultHttpClient(defaultConnectionManager(Integer.MAX_VALUE, Integer.MAX_VALUE), defaultParams(DEFAULT_TIMEOUT)), null, true);
}
public CommonsHttpClient(int timeout, String userAgentPassword, boolean gzip) {
this(new DefaultHttpClient(defaultConnectionManager(Integer.MAX_VALUE, Integer.MAX_VALUE), defaultParams(timeout)), userAgentPassword, gzip);
}
public CommonsHttpClient(DefaultHttpClient client, String userAgentPassword, boolean gzip) {
this.defaultHeaders = new ConcurrentHashMap<String, String>();
this.userAgentPassword = userAgentPassword;
this.httpClient = client;
// ask the server if we can use gzip
if( gzip ) this.addDefaultHeader(ACCEPT_ENCODING, DEFLATE_ENCODINGS);
}
public DefaultHttpClient getHttpClient(){
return this.httpClient;
}
//----------------------method implementations
@Override
public void setUserCredentials(String userName, String password) {
UsernamePasswordCredentials creds = new UsernamePasswordCredentials(userName, password);
this.httpClient.getCredentialsProvider().setCredentials(AuthScope.ANY, creds);
}
@Override
public RetsHttpResponse doRequest(String httpMethod, RetsHttpRequest request) throws RetsException {
return "GET".equals(StringUtils.upperCase(httpMethod)) ? this.doGet(request) : this.doPost(request);
}
//----------------------method implementations
public RetsHttpResponse doGet(RetsHttpRequest request) throws RetsException {
String url = request.getUrl();
String args = request.getHttpParameters();
if (args != null) {
url = url + "?" + args;
}
HttpGet method = new HttpGet(url);
return execute(method, request.getHeaders());
}
public RetsHttpResponse doPost(RetsHttpRequest request) throws RetsException {
String url = request.getUrl();
String body = request.getHttpParameters();
if (body == null) body = ""; // commons-httpclient 3.0 refuses to accept null entity (body)
HttpPost method = new HttpPost(url);
try {
method.setEntity(new StringEntity(body, null, null));
} catch (UnsupportedEncodingException e) {
throw new RetsException(e);
}
//updated Content-Type, application/x-www-url-encoded no longer supported
method.setHeader("Content-Type", "application/x-www-form-urlencoded");
return execute(method, request.getHeaders());
}
protected RetsHttpResponse execute(final HttpRequestBase method, Map<String,String> headers) throws RetsException {
try {
// add the default headers
if (this.defaultHeaders != null) {
for (Map.Entry<String,String> entry : this.defaultHeaders.entrySet()) {
method.setHeader(entry.getKey(), entry.getValue());
}
}
// add our request headers from rets
if (headers != null) {
for (Map.Entry<String,String> entry : headers.entrySet()) {
method.setHeader(entry.getKey(), entry.getValue());
}
}
// optional ua-auth stuff here
if( this.userAgentPassword != null ){
method.setHeader(RETS_UA_AUTH_HEADER, calculateUaAuthHeader(method,getCookies()));
}
// try to execute the request
HttpResponse response = this.httpClient.execute(method);
StatusLine status = response.getStatusLine();
if (status.getStatusCode() != HttpStatus.SC_OK) {
throw new InvalidHttpStatusException(status);
}
return new CommonsHttpClientResponse(response, getCookies());
} catch (Exception e) {
throw new RetsException(e);
}
}
@Override
public synchronized void addDefaultHeader(String key, String value) {
this.defaultHeaders.put(key, value);
if( value == null ) this.defaultHeaders.remove(key);
}
protected Map<String,String> getCookies() {
Map<String,String> cookieMap = new CaseInsensitiveTreeMap();
for (Cookie cookie : this.httpClient.getCookieStore().getCookies()) {
cookieMap.put(cookie.getName(), cookie.getValue());
}
return cookieMap;
}
protected String calculateUaAuthHeader(HttpRequestBase method, Map<String, String> cookies ) {
final String userAgent = this.getHeaderValue(method, USER_AGENT);
final String requestId = this.getHeaderValue(method, RETS_REQUEST_ID);
final String sessionId = cookies.get(RETS_SESSION_ID);
final String retsVersion = this.getHeaderValue(method, RETS_VERSION);
String secretHash = DigestUtils.md5Hex(String.format("%s:%s",userAgent,this.userAgentPassword));
String pieces = String.format("%s:%s:%s:%s",secretHash,StringUtils.trimToEmpty(requestId),StringUtils.trimToEmpty(sessionId),retsVersion);
return String.format("Digest %s", DigestUtils.md5Hex(pieces));
}
protected String getHeaderValue(HttpRequestBase method, String key){
Header requestHeader = method.getFirstHeader(key);
if( requestHeader == null ) return null;
return requestHeader.getValue();
}
}

View File

@ -0,0 +1,110 @@
package com.ossez.usreio.client;
import java.io.IOException;
import java.io.InputStream;
import java.util.Map;
import java.util.zip.GZIPInputStream;
import com.ossez.usreio.common.util.CaseInsensitiveTreeMap;
import org.apache.commons.lang3.ArrayUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.http.Header;
import org.apache.http.HttpResponse;
import com.google.common.io.Closeables;
public class CommonsHttpClientResponse implements RetsHttpResponse {
private HttpResponse response;
private Map<String,String> headers;
private Map<String,String> cookies;
public CommonsHttpClientResponse(HttpResponse response, Map<String,String> cookies) {
this.response = response;
this.cookies = new CaseInsensitiveTreeMap<String,String>(cookies);
this.headers = new CaseInsensitiveTreeMap<String,String>();
for (Header header : this.response.getAllHeaders()) {
this.headers.put(header.getName(), header.getValue());
}
}
public int getResponseCode() {
return this.response.getStatusLine().getStatusCode();
}
public Map<String,String> getHeaders() {
return this.headers;
}
public String getHeader(String header) {
return this.headers.get(header);
}
public Map<String,String> getCookies() throws RetsException {
return this.cookies;
}
public String getCookie(String cookie) throws RetsException {
return this.cookies.get(cookie);
}
public String getCharset() {
String contentType = StringUtils.trimToEmpty(this.getHeader(CommonsHttpClient.CONTENT_TYPE)).toLowerCase();
String[] split = StringUtils.split(contentType, ";");
if (split == null) return null;
for (String s : split) {
String sLower = s.toLowerCase().trim();
boolean b = sLower.startsWith("charset=");
if (b){
return StringUtils.substringAfter(s, "charset=");
}
}
return null;
}
/** using this mess to provide logging, gzipping and httpmethod closing */
public InputStream getInputStream() throws RetsException {
try {
// get our underlying stream
InputStream inputStream = this.response.getEntity().getContent();
// gzipped aware checks
String contentEncoding = StringUtils.trimToEmpty(this.getHeader(CommonsHttpClient.CONTENT_ENCODING)).toLowerCase();
boolean gzipped = ArrayUtils.contains(CommonsHttpClient.DEFLATE_ENCODINGS.split(","),contentEncoding);
if( gzipped ) inputStream = new GZIPInputStream(inputStream);
final InputStream in = inputStream;
// the http method close wrapper (necessary)
return new InputStream(){
public int read() throws IOException {
return in.read();
}
public int read(byte[] b) throws IOException {
return in.read(b);
}
public int read(byte[] b, int off, int len) throws IOException {
return in.read(b, off, len);
}
public void close() throws IOException {
// connection release _AFTER_ the input stream has been read
try {
Closeables.close(in, true);
} catch (IOException e) {
// ignore
}
}
};
} catch (IOException e) {
throw new RetsException(e);
}
}
}

View File

@ -0,0 +1,56 @@
package com.ossez.usreio.client;
import org.apache.commons.logging.LogFactory;
public interface CompactRowPolicy {
/** fail fast and furiously */
public static final CompactRowPolicy STRICT = new CompactRowPolicy(){
public boolean apply(int row, String[] columns, String[] values) {
if( values.length != columns.length )
throw new IllegalArgumentException(String.format("Invalid number of result columns: got %s, expected %s",values.length, columns.length));
return true;
}};
/** drop everything thats suspect */
public static final CompactRowPolicy DROP = new CompactRowPolicy(){
public boolean apply(int row, String[] columns, String[] values) {
if (values.length != columns.length) {
LogFactory.getLog(CompactRowPolicy.class).warn(String.format("Row %s: Invalid number of result columns: got %s, expected ",row, values.length, columns.length));
return false;
}
return true;
}};
/** fail fast on long rows */
public static final CompactRowPolicy DEFAULT = new CompactRowPolicy(){
public boolean apply(int row, String[] columns, String[] values) {
if (values.length > columns.length) {
throw new IllegalArgumentException(String.format("Invalid number of result columns: got %s, expected %s",values.length, columns.length));
}
if (values.length < columns.length) {
LogFactory.getLog(CompactRowPolicy.class).warn(String.format("Row %s: Invalid number of result columns: got %s, expected ",row, values.length, columns.length));
}
return true;
}};
/** drop and log long rows, try to keep short rows */
public static final CompactRowPolicy DROP_LONG = new CompactRowPolicy(){
public boolean apply(int row, String[] columns, String[] values) {
if (values.length > columns.length) {
LogFactory.getLog(CompactRowPolicy.class).warn(String.format("Row %s: Invalid number of result columns: got %s, expected ",row, values.length, columns.length));
return false;
}
if (values.length < columns.length) {
LogFactory.getLog(CompactRowPolicy.class).warn(String.format("Row %s: Invalid number of result columns: got %s, expected ",row, values.length, columns.length));
}
return true;
}};
public boolean apply(int row, String[] columns, String[] values);
}

View File

@ -0,0 +1,36 @@
package com.ossez.usreio.client;
/**
* on the off chance you need an ad hoc request object...
*/
public class GenericHttpRequest extends VersionInsensitiveRequest {
public GenericHttpRequest(){
// noop
}
public GenericHttpRequest(String url){
this.mUrl = url;
}
/**
* throws an exception. GenericHttpRequest can't have a
* CapabilityUrl
* @param urls the CapabilityUrls object that has nothing we can use
*/
@Override
public void setUrl(CapabilityUrls urls) {
// do nothing
return;
}
/**
* expose the queryParameter interface to build query arguments.
* @param name the parameter name
* @param value the parameter value
*/
@Override
public void setQueryParameter(String name, String value) {
super.setQueryParameter(name, value);
}
}

View File

@ -0,0 +1,73 @@
package com.ossez.usreio.client;
import org.apache.commons.lang3.StringUtils;
public class GetMetadataRequest extends VersionInsensitiveRequest {
private static final int COMPACT_FORMAT = 0;
private static final int STANDARD_XML_FORMAT = 1;
public static final String KEY_TYPE = "Type";
public static final String KEY_ID = "ID";
public static final String KEY_FORMAT = "Format";
public static final String FORMAT_STANDARD = "STANDARD-XML";
public static final String FORMAT_STANDARD_PREFIX = "STANDARD-XML:";
public static final String FORMAT_COMPACT = "COMPACT";
private int format;
private String standardXmlVersion;
public GetMetadataRequest(String type, String id) throws RetsException {
this(type, new String[] { id });
}
public GetMetadataRequest(String type, String[] ids) throws RetsException {
assertValidIds(ids);
type = "METADATA-" + type;
if (type.equals("METADATA-SYSTEM") || type.equals("METADATA-RESOURCE")) {
assertIdZeroOrStar(ids);
}
setQueryParameter(KEY_TYPE, type);
setQueryParameter(KEY_ID, StringUtils.join(ids, ":"));
setQueryParameter(KEY_FORMAT, FORMAT_STANDARD);
this.format = STANDARD_XML_FORMAT;
}
@Override
public void setUrl(CapabilityUrls urls) {
setUrl(urls.getGetMetadataUrl());
}
private void assertValidIds(String[] ids) throws InvalidArgumentException {
if (ids.length == 0) {
throw new InvalidArgumentException("Expecting at least one ID");
}
}
private void assertIdZeroOrStar(String[] ids) throws InvalidArgumentException {
if (ids.length != 1) {
throw new InvalidArgumentException("Expecting 1 ID, but found, " + ids.length);
}
if (!ids[0].equals("0") && !ids[0].equals("*")) {
throw new InvalidArgumentException("Expecting ID of 0 or *, but was " + ids[0]);
}
}
public void setCompactFormat() {
setQueryParameter(KEY_FORMAT, FORMAT_COMPACT);
this.format = COMPACT_FORMAT;
this.standardXmlVersion = null;
}
public boolean isCompactFormat() {
return (this.format == COMPACT_FORMAT);
}
public boolean isStandardXmlFormat() {
return (this.format == STANDARD_XML_FORMAT);
}
public String getStandardXmlVersion() {
return this.standardXmlVersion;
}
}

View File

@ -0,0 +1,80 @@
package com.ossez.usreio.client;
import java.io.InputStream;
import java.util.List;
import com.ossez.usreio.tests.common.metadata.JDomCompactBuilder;
import com.ossez.usreio.tests.common.metadata.JDomStandardBuilder;
import com.ossez.usreio.tests.common.metadata.MetaObject;
import com.ossez.usreio.tests.common.metadata.MetadataException;
import org.apache.commons.lang3.math.NumberUtils;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;
public class GetMetadataResponse {
private MetaObject[] mMetadataObjs;
public GetMetadataResponse(InputStream stream, boolean compact, boolean isStrict) throws RetsException {
try {
SAXReader builder = new SAXReader();
Document document = builder.read(stream);
Element retsElement = document.getRootElement();
if (!retsElement.getName().equals("RETS")) {
throw new RetsException("Expecting RETS");
}
int replyCode = NumberUtils.toInt(retsElement.attributeValue("ReplyCode"));
if (ReplyCode.SUCCESS.equals(replyCode)) {
if (compact) {
handleCompactMetadata(document, isStrict);
} else {
handleStandardMetadata(document, isStrict);
}
} else if (ReplyCode.NO_METADATA_FOUND.equals(replyCode)) {
// No metadata is not an exceptional case
handleNoMetadataFound(retsElement);
} else {
InvalidReplyCodeException e = new InvalidReplyCodeException(replyCode);
e.setRemoteMessage(retsElement.attributeValue(retsElement.attributeValue("ReplyText")));
throw e;
}
} catch (DocumentException e) {
throw new RetsException(e);
}
}
private void handleNoMetadataFound(Element retsElement) throws RetsException {
List children = retsElement.elements();
if (children.size() != 0) {
throw new RetsException("Expecting 0 children when results");
}
this.mMetadataObjs = new MetaObject[0];
}
private void handleCompactMetadata(Document document, boolean isStrict) throws RetsException {
try {
JDomCompactBuilder builder = new JDomCompactBuilder();
builder.setStrict(isStrict);
this.mMetadataObjs = builder.parse(document);
} catch (MetadataException e) {
throw new RetsException(e);
}
}
private void handleStandardMetadata(Document document, boolean isStrict) throws RetsException {
try {
JDomStandardBuilder builder = new JDomStandardBuilder();
builder.setStrict(isStrict);
this.mMetadataObjs = builder.parse(document);
} catch (MetadataException e) {
throw new RetsException(e);
}
}
public MetaObject[] getMetadata() {
return this.mMetadataObjs;
}
}

View File

@ -0,0 +1,12 @@
package com.ossez.usreio.client;
import java.io.Closeable;
import java.util.Iterator;
/**
* Iterator for SingleResoponseObjects
* @param <G>
*/
public interface GetObjectIterator<G extends SingleObjectResponse> extends Closeable, Iterator<G>{
// noop
}

View File

@ -0,0 +1,101 @@
package com.ossez.usreio.client;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;
import java.util.Map;
import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.lang3.StringUtils;
public class GetObjectRequest extends VersionInsensitiveRequest {
public static final String KEY_RESOURCE = "Resource";
public static final String KEY_TYPE = "Type";
public static final String KEY_LOCATION = "Location";
public static final String KEY_ID = "ID";
private final Map mMap;
public GetObjectRequest(String resource, String type) {
this(resource, type, new String[] { "*/*" });
}
public GetObjectRequest(String resource, String type, String[] acceptMimeTypes) {
setQueryParameter(KEY_RESOURCE, resource);
setQueryParameter(KEY_TYPE, type);
this.mMap = new HashMap();
setHeader("Accept", StringUtils.join(acceptMimeTypes, ", "));
}
@Override
public void setUrl(CapabilityUrls urls) {
setUrl(urls.getGetObjectUrl());
}
public void setLocationOnly(boolean flag) {
if (flag) {
setQueryParameter(KEY_LOCATION, "1");
} else {
setQueryParameter(KEY_LOCATION, null);
}
}
public void addObject(String resourceEntity, String id) {
if (id == null)
throw new NullPointerException("Object id should not be null. "
+ "Cannot remove object already added to request.");
Object cur = this.mMap.get(resourceEntity);
if (id.equals("*")) {
this.mMap.put(resourceEntity, id);
} else if (cur == null) {
this.mMap.put(resourceEntity, id);
} else if (cur instanceof String) {
if (ObjectUtils.equals(cur, "*")) {
return;
}
if (ObjectUtils.equals(cur, id)) {
return;
}
Set s = new HashSet();
s.add(cur);
s.add(id);
this.mMap.put(resourceEntity, s);
} else if (cur instanceof Set) {
((Set) cur).add(id);
} else {
/* NOTREACHED */
throw new RuntimeException(resourceEntity + " has invalid value " + "of type " + cur.getClass().getName());
}
setQueryParameter(KEY_ID, makeIdStr());
}
private String makeIdStr() {
StringBuffer id = new StringBuffer();
Iterator iter = this.mMap.keySet().iterator();
while (iter.hasNext()) {
String key = (String) iter.next();
id.append(key);
Object cur = this.mMap.get(key);
if (cur instanceof String) {
id.append(":");
id.append(cur);
} else if (cur instanceof Set) {
Iterator iter2 = ((Set) cur).iterator();
while (iter2.hasNext()) {
String val = (String) iter2.next();
id.append(":");
id.append(val);
}
} else {
throw new RuntimeException(key + " has invalid value of " + "type " + cur.getClass().getName());
}
if (iter.hasNext()) {
id.append(",");
}
}
return id.toString();
}
}

View File

@ -0,0 +1,188 @@
package com.ossez.usreio.client;
import java.io.IOException;
import java.io.InputStream;
import java.util.Map;
import java.util.NoSuchElementException;
import com.ossez.usreio.common.util.CaseInsensitiveTreeMap;
import org.apache.commons.lang3.math.NumberUtils;
import org.apache.http.HeaderElement;
import org.apache.http.NameValuePair;
import org.apache.http.message.BasicHeaderValueParser;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;
public class GetObjectResponse{
private static final int DEFAULT_BUFFER_SIZE = 8192;
private final static GetObjectIterator<SingleObjectResponse> EMPTY_OBJECT_RESPONSE_ITERATOR = new GetObjectIterator<SingleObjectResponse>() {
public boolean hasNext() {
return false;
}
public SingleObjectResponse next() {
throw new NoSuchElementException();
}
public void close() {
/* no op */
}
public void remove() {
/* no op */
}
};
private final Map headers;
private final InputStream inputStream;
private final boolean isMultipart;
/** Indicate whether the response was empty */
private boolean emptyResponse;
/** Indicate whether this GetObjectResponse is exhausted, i.e. has no objects */
private boolean exhausted;
public GetObjectResponse(Map headers, InputStream in) throws RetsException {
this.emptyResponse = false;
this.exhausted = false;
this.headers = new CaseInsensitiveTreeMap(headers);
this.isMultipart = getType().contains("multipart");
this.inputStream = in;
boolean isXml = getType().equals("text/xml");
boolean containsContentId = headers.containsKey(SingleObjectResponse.CONTENT_ID);
// non multipart request that returns text/xml and does NOT have a Context-ID header, must only be a non-zero response code
boolean nonMultiPart_xml_withoutContentId = !this.isMultipart && isXml && !containsContentId;
// multipart request that returns text/xml can only be a non-zero response code
boolean multiPart_xml = this.isMultipart && isXml;
if ( multiPart_xml || nonMultiPart_xml_withoutContentId ) {
int replyCode = 0;
try {
// GetObjectResponse is empty, because we have a Rets ReplyCode
this.emptyResponse = true;
SAXReader builder = new SAXReader();
Document mDocument = builder.read(in);
Element root = mDocument.getRootElement();
if (root.getName().equals("RETS")) {
replyCode = NumberUtils.toInt(root.attributeValue("ReplyCode"));
// success
if (ReplyCode.SUCCESS.equals(replyCode)) return;
// no object found - that's fine
if (ReplyCode.NO_OBJECT_FOUND.equals(replyCode)) return;
throw new InvalidReplyCodeException(replyCode);
}
// no other possibilities
throw new RetsException("Malformed response [multipart="+this.isMultipart+", content-type=text/xml]. " +
"Content id did not exist in response and response was not valid rets response.");
} catch (DocumentException e) {
throw new RetsException(e);
}
}
}
public String getType() {
return (String) this.headers.get("Content-Type");
}
public String getBoundary() {
String contentTypeValue = getType();
HeaderElement[] contentType = BasicHeaderValueParser.parseElements(contentTypeValue, new BasicHeaderValueParser());
if (contentType.length != 1)
throw new IllegalArgumentException("Multipart response appears to have a bad Content-Type: header value: "
+ contentTypeValue);
NameValuePair boundaryNV = contentType[0].getParameterByName("boundary");
if (boundaryNV == null)
return null;
return unescapeBoundary(boundaryNV.getValue());
}
private static String unescapeBoundary(String boundaryValue) {
if (boundaryValue.startsWith("\""))
boundaryValue = boundaryValue.substring(1);
if (boundaryValue.endsWith("\""))
boundaryValue = boundaryValue.substring(0, boundaryValue.length() - 1);
return boundaryValue;
}
/**
* @return GetObjectIterator, which iterates over SingleObjectResponse
* objects.
*
* @throws RetsException
*/
public <T extends SingleObjectResponse> GetObjectIterator<T> iterator() throws RetsException {
return iterator(DEFAULT_BUFFER_SIZE);
}
/**
* @return GetObjectIterator, which iterates over SingleObjectResponse
* objects.
*
* @param bufferSize How large a buffer should be used for underlying
* streams.
*
* @throws RetsException
*/
public <T extends SingleObjectResponse> GetObjectIterator<T> iterator(int bufferSize) throws RetsException {
if(this.exhausted )
throw new RetsException("response was exhausted - cannot request iterator a second time");
if( this.emptyResponse )
return (GetObjectIterator<T>) EMPTY_OBJECT_RESPONSE_ITERATOR;
if( this.isMultipart ){
try {
return GetObjectResponseIterator.createIterator(this, bufferSize);
} catch (Exception e) {
throw new RetsException("Error creating multipart GetObjectIterator", e);
}
}
// no other possibilities
return new NonMultipartGetObjectResponseIterator(this.headers, this.inputStream);
}
public InputStream getInputStream() {
return this.inputStream;
}
}
/** Used to implement GetObjectIterator for a non multipart response. */
final class NonMultipartGetObjectResponseIterator implements GetObjectIterator {
private boolean exhausted;
private final Map headers;
private final InputStream inputStream;
public NonMultipartGetObjectResponseIterator(Map headers, InputStream in){
this.exhausted = false;
this.headers = headers;
this.inputStream = in;
}
public void close() throws IOException {
this.inputStream.close();
}
public void remove() {
throw new UnsupportedOperationException();
}
public boolean hasNext() {
return !this.exhausted;
}
public SingleObjectResponse next() {
if( this.exhausted )
throw new NoSuchElementException("stream exhausted");
this.exhausted = true;
return new SingleObjectResponse(this.headers, this.inputStream);
}
}

View File

@ -0,0 +1,140 @@
package com.ossez.usreio.client;
import java.io.BufferedInputStream;
import java.io.IOException;
import java.io.PushbackInputStream;
import java.util.HashMap;
import java.util.Map;
import java.util.NoSuchElementException;
import org.apache.commons.lang3.StringUtils;
public class GetObjectResponseIterator<T extends SingleObjectResponse> implements GetObjectIterator<T> {
public static final char CR = '\r';
public static final char LF = '\n';
public static final String EOL = CR+""+LF;
public static final String BS = "--";
private final PushbackInputStream multipartStream;
private final String boundary;
private Boolean hasNext;
public static <T extends SingleObjectResponse> GetObjectIterator<T> createIterator(final GetObjectResponse response, int streamBufferSize) throws Exception {
String boundary = response.getBoundary();
if (boundary != null)
return new GetObjectResponseIterator(response, boundary, streamBufferSize);
return new GetObjectIterator<T>() {
public void close() throws IOException{
response.getInputStream().close();
}
public boolean hasNext() {
return false;
}
public T next() {
throw new NoSuchElementException();
}
public void remove() {
throw new UnsupportedOperationException("");
}
};
}
private GetObjectResponseIterator(GetObjectResponse response, String boundary, int streamBufferSize) throws Exception {
this.boundary = boundary;
BufferedInputStream input = new BufferedInputStream(response.getInputStream(), streamBufferSize);
this.multipartStream = new PushbackInputStream(input, BS.length() + this.boundary.length() + EOL.length());
}
public boolean hasNext() {
if (this.hasNext != null)
return this.hasNext.booleanValue();
try {
this.hasNext = new Boolean(this.getHaveNext());
return this.hasNext.booleanValue();
} catch (IOException e) {
throw new RuntimeException(e);
}
}
public T next() {
if (!this.hasNext())
throw new NoSuchElementException();
this.hasNext = null;
try {
return getNext();
} catch (Exception e) {
throw new RuntimeException(e);
}
}
public void remove() {
throw new UnsupportedOperationException();
}
public void close() throws IOException {
this.multipartStream.close();
}
private boolean getHaveNext() throws IOException {
String line = null;
while ((line = this.readLine()) != null) {
if (line.equals(BS+this.boundary))
return true;
if (line.equals(BS+this.boundary+BS))
return false;
}
return false;
}
private T getNext() throws Exception {
Map headers = new HashMap();
String header = null;
while (StringUtils.isNotEmpty(header = this.readLine())) {
int nvSeperatorIndex = header.indexOf(':');
if (nvSeperatorIndex == -1){
headers.put(header, "");
} else {
String name = header.substring(0, nvSeperatorIndex);
String value = header.substring(nvSeperatorIndex + 1).trim();
headers.put(name, value);
}
}
return (T)new SingleObjectResponse(headers, new SinglePartInputStream(this.multipartStream, BS+this.boundary));
}
// TODO find existing library to do this
private String readLine() throws IOException {
boolean eolReached = false;
StringBuffer line = new StringBuffer();
int currentChar = -1;
while (!eolReached && (currentChar = this.multipartStream.read()) != -1) {
eolReached = (currentChar == CR || currentChar == LF);
if (!eolReached)
line.append((char) currentChar);
}
if (currentChar == -1 && line.length() == 0)
return null;
if (currentChar == CR) {
int nextChar = this.multipartStream.read();
if (nextChar != LF)
this.multipartStream.unread(new byte[] { (byte) nextChar });
}
return line.toString();
}
}

View File

@ -0,0 +1,7 @@
package com.ossez.usreio.client;
public class InvalidArgumentException extends RetsException {
public InvalidArgumentException(String message) {
super(message);
}
}

View File

@ -0,0 +1,12 @@
package com.ossez.usreio.client;
import org.apache.http.StatusLine;
public class InvalidHttpStatusException extends RetsException {
public InvalidHttpStatusException(StatusLine status) {
super("Status code (" + status.getStatusCode() + ") " + status.getReasonPhrase());
}
public InvalidHttpStatusException(StatusLine status, String message) {
super("Status code (" + status.getStatusCode() + ") " + status.getReasonPhrase() +" '"+message+"'");
}
}

View File

@ -0,0 +1,44 @@
package com.ossez.usreio.client;
import org.apache.commons.lang3.SystemUtils;
/**
* Exception class for invalid reply codes from a Rets server
*/
public class InvalidReplyCodeException extends RetsException {
private final ReplyCode mReplyCode;
private String mMsg;
private String mReqinfo;
public InvalidReplyCodeException(int replyCodeValue) {
this.mReplyCode = ReplyCode.fromValue(replyCodeValue);
}
public InvalidReplyCodeException(ReplyCode replyCode) {
this.mReplyCode = replyCode;
}
@Override
public String getMessage() {
StringBuffer sb = new StringBuffer(this.mReplyCode.toString());
if (this.mMsg != null) {
sb.append(SystemUtils.LINE_SEPARATOR + this.mMsg);
}
if (this.mReqinfo != null) {
sb.append(SystemUtils.LINE_SEPARATOR + this.mReqinfo);
}
return sb.toString();
}
public int getReplyCodeValue() {
return this.mReplyCode.getValue();
}
public void setRemoteMessage(String msg) {
this.mMsg = msg;
}
public void setRequestInfo(String reqinfo) {
this.mReqinfo = reqinfo;
}
}

View File

@ -0,0 +1,17 @@
package com.ossez.usreio.client;
public interface InvalidReplyCodeHandler {
InvalidReplyCodeHandler FAIL = new InvalidReplyCodeHandler() {
public void invalidRetsReplyCode(int replyCode) throws InvalidReplyCodeException {
throw new InvalidReplyCodeException(replyCode);
}
public void invalidRetsStatusReplyCode(int replyCode) throws InvalidReplyCodeException {
throw new InvalidReplyCodeException(replyCode);
}
};
public void invalidRetsReplyCode(int replyCode) throws InvalidReplyCodeException;
public void invalidRetsStatusReplyCode(int replyCode) throws InvalidReplyCodeException;
}

View File

@ -0,0 +1,140 @@
package com.ossez.usreio.client;
import org.apache.commons.lang3.ArrayUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.math.NumberUtils;
import org.apache.commons.logging.Log;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.InputStream;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import static com.ossez.usreio.client.CapabilityUrls.LOGIN_URL;
/**
* Process key and Value
*
* @author YuCheng Hu
*/
abstract public class KeyValueResponse {
protected static final String CRLF = "\r\n";
private static final Logger logger = LoggerFactory.getLogger(KeyValueResponse.class);
protected Document mDoc;
protected int mReplyCode;
protected boolean mStrict;
public KeyValueResponse() {
this.mStrict = false;
}
public void parse(InputStream stream, RetsVersion mVersion) throws RetsException {
try {
SAXReader builder = new SAXReader();
this.mDoc = builder.read(stream);
Element retsElement = this.mDoc.getRootElement();
if (!retsElement.getName().equals("RETS")) {
throw new RetsException("Expecting RETS");
}
int replyCode = NumberUtils.toInt(retsElement.attributeValue("ReplyCode"));
this.mReplyCode = replyCode;
if (!isValidReplyCode(replyCode)) {
throw new InvalidReplyCodeException(replyCode);
}
Element capabilityContainer;
if (RetsVersion.RETS_10.equals(mVersion)) {
capabilityContainer = retsElement;
} else {
List children = retsElement.elements();
if (children.size() != 1) {
throw new RetsException("Invalid number of children: " + children.size());
}
capabilityContainer = (Element) children.get(0);
if (!capabilityContainer.getName().equals("RETS-RESPONSE")) {
throw new RetsException("Expecting RETS-RESPONSE");
}
}
this.handleRetsResponse(capabilityContainer);
} catch (DocumentException e) {
throw new RetsException(e);
}
}
protected boolean isValidReplyCode(int replyCode) {
return (ReplyCode.SUCCESS.equals(replyCode));
}
/**
* handleRetsResponse
*
* @param retsResponse
* @throws RetsException
*/
private void handleRetsResponse(Element retsResponse) throws RetsException {
List<String> tokenizeList = Arrays.asList(StringUtils.split(retsResponse.getText(), CRLF));
HashMap<String, String> retsResponseMap = new HashMap<String, String>();
for (String keyValueStr : tokenizeList) {
String[] splits = StringUtils.split(keyValueStr, "=");
if (!ArrayUtils.isEmpty(splits) && splits.length > 1) {
String key = StringUtils.trimToNull(splits[0]);
String value = StringUtils.trimToEmpty(splits[1]);
// PROCESS LOGIN_URL
if (StringUtils.equalsIgnoreCase(LOGIN_URL, key)) {
retsResponseMap.put(LOGIN_URL, value);
this.handleKeyValue(LOGIN_URL, value);
} else
retsResponseMap.put(key, value);
}
}
retsResponseMap.entrySet().parallelStream().forEach(entry -> {
try {
this.handleKeyValue(entry.getKey(), entry.getValue());
} catch (RetsException ex) {
logger.warn("Unable process rests login response value", ex);
}
});
}
protected abstract void handleKeyValue(String key, String value) throws RetsException;
public void setStrict(boolean strict) {
this.mStrict = strict;
}
public boolean isStrict() {
return this.mStrict;
}
protected boolean matchKey(String key, String value) {
if (this.mStrict)
return key.equals(value);
return key.equalsIgnoreCase(value);
}
protected void assertStrictWarning(Log log, String message) throws RetsException {
if (this.mStrict)
throw new RetsException(message);
log.warn(message);
}
}

View File

@ -0,0 +1,23 @@
package com.ossez.usreio.client;
public class LoginRequest extends VersionInsensitiveRequest {
@Override
public void setUrl(CapabilityUrls urls) {
setUrl(urls.getLoginUrl());
}
public void setBrokerCode(String code, String branch) {
if (code == null) {
setQueryParameter(KEY_BROKERCODE, null);
} else {
if (branch == null) {
setQueryParameter(KEY_BROKERCODE, code);
} else {
setQueryParameter(KEY_BROKERCODE, code + "," + branch);
}
}
}
public static final String KEY_BROKERCODE = "BrokerCode";
}

View File

@ -0,0 +1,200 @@
package com.ossez.usreio.client;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.math.NumberUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import java.io.InputStream;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.HashSet;
import java.util.Set;
/**
* @author YuCheng Hu
*/
public class LoginResponse extends KeyValueResponse {
private static final String BROKER_KEY = "Broker";
private static final String MEMBER_NAME_KEY = "MemberName";
private static final String METADATA_VER_KEY = "MetadataVersion";
private static final String MIN_METADATA_VER_KEY = "MinMetadataVersion";
private static final String USER_INFO_KEY = "User";
private static final String OFFICE_LIST_KEY = "OfficeList";
private static final String BALANCE_KEY = "Balance";
private static final String TIMEOUT_KEY = "TimeoutSeconds";
private static final String PWD_EXPIRE_KEY = "Expr";
private static final String METADATA_TIMESTAMP_KEY = "MetadataTimestamp";
private static final String MIN_METADATA_TIMESTAMP_KEY = "MinMetadataTimestamp";
private static final Log LOG = LogFactory.getLog(LoginResponse.class);
private String sessionId;
private String memberName;
private String userInformation;
private String broker;
private String metadataVersion;
private String minMetadataVersion;
private String metadataTimestamp;
private String minMetadataTimestamp;
private String officeList;
private String balance;
private int sessionTimeout;
private String passwordExpiration;
private CapabilityUrls capabilityUrls;
private Set brokerCodes;
public LoginResponse(String loginUrl) {
super();
this.brokerCodes = new HashSet();
URL url = null;
try {
url = new URL(loginUrl);
} catch (MalformedURLException e) {
LOG.warn("Bad URL: " + loginUrl);
}
this.capabilityUrls = new CapabilityUrls(url);
}
public LoginResponse() {
super();
this.capabilityUrls = new CapabilityUrls();
}
@Override
public void parse(InputStream stream, RetsVersion version) throws RetsException {
super.parse(stream, version);
if (ReplyCode.BROKER_CODE_REQUIRED.equals(this.mReplyCode)) {
throw new BrokerCodeRequredException(this.brokerCodes);
}
}
@Override
protected boolean isValidReplyCode(int replyCode) {
return (super.isValidReplyCode(replyCode) || ReplyCode.BROKER_CODE_REQUIRED.equals(replyCode));
}
@Override
protected void handleKeyValue(String key, String value) throws RetsException {
if (ReplyCode.BROKER_CODE_REQUIRED.equals(this.mReplyCode)) {
if (matchKey(key, BROKER_KEY)) {
String[] strings = StringUtils.split(value, ",");
if (strings.length > 0 && strings.length < 3) {
this.brokerCodes.add(strings);
} else {
throw new RetsException("Invalid broker/branch code: " + value);
}
}
}
if (matchKey(key, BROKER_KEY)) {
this.broker = value;
} else if (matchKey(key, MEMBER_NAME_KEY)) {
this.memberName = value;
} else if (matchKey(key, METADATA_VER_KEY)) {
this.metadataVersion = value;
} else if (matchKey(key, MIN_METADATA_VER_KEY)) {
this.minMetadataVersion = value;
} else if (matchKey(key, METADATA_TIMESTAMP_KEY)) {
this.metadataTimestamp = value;
} else if (matchKey(key, MIN_METADATA_TIMESTAMP_KEY)) {
this.minMetadataTimestamp = value;
} else if (matchKey(key, USER_INFO_KEY)) {
this.userInformation = value;
} else if (matchKey(key, OFFICE_LIST_KEY)) {
this.officeList = value;
} else if (matchKey(key, BALANCE_KEY)) {
this.balance = value;
} else if (matchKey(key, TIMEOUT_KEY)) {
this.sessionTimeout = NumberUtils.toInt(value);
} else if (matchKey(key, PWD_EXPIRE_KEY)) {
this.passwordExpiration = value;
} else if (matchKey(key, CapabilityUrls.ACTION_URL)) {
this.capabilityUrls.setActionUrl(value);
} else if (matchKey(key, CapabilityUrls.CHANGE_PASSWORD_URL)) {
this.capabilityUrls.setChangePasswordUrl(value);
} else if (matchKey(key, CapabilityUrls.GET_OBJECT_URL)) {
this.capabilityUrls.setGetObjectUrl(value);
} else if (matchKey(key, CapabilityUrls.LOGIN_URL)) {
this.capabilityUrls.setLoginUrl(value);
} else if (matchKey(key, CapabilityUrls.LOGIN_COMPLETE_URL)) {
this.capabilityUrls.setLoginCompleteUrl(value);
} else if (matchKey(key, CapabilityUrls.LOGOUT_URL)) {
this.capabilityUrls.setLogoutUrl(value);
} else if (matchKey(key, CapabilityUrls.SEARCH_URL)) {
this.capabilityUrls.setSearchUrl(value);
} else if (matchKey(key, CapabilityUrls.GET_METADATA_URL)) {
this.capabilityUrls.setGetMetadataUrl(value);
} else if (matchKey(key, CapabilityUrls.UPDATE_URL)) {
this.capabilityUrls.setUpdateUrl(value);
} else if (matchKey(key, CapabilityUrls.SERVER_INFO_URL)) {
this.capabilityUrls.setServerInfo(value);
LOG.warn("Depreciated: " + key + " -> " + value);
} else if (matchKey(key, "Get")) {
LOG.warn("Found bad key: Get -> " + value);
// FIX ME: Should not get this
} else {
if (key.substring(0, 2).equalsIgnoreCase("X-")) {
LOG.warn("Unknown experimental key: " + key + " -> " + value);
} else {
assertStrictWarning(LOG, "Invalid login response key: " + key + " -> " + value);
}
}
}
public String getMemberName() {
return this.memberName;
}
public String getUserInformation() {
return this.userInformation;
}
public String getBroker() {
return this.broker;
}
public String getMetadataVersion() {
return this.metadataVersion;
}
public String getMinMetadataVersion() {
return this.minMetadataVersion;
}
public String getMetadataTimestamp() {
return this.metadataTimestamp;
}
public String getMinMetadataTimestamp() {
return this.minMetadataTimestamp;
}
public String getOfficeList() {
return this.officeList;
}
public String getBalance() {
return this.balance;
}
public int getSessionTimeout() {
return this.sessionTimeout;
}
public String getPasswordExpiration() {
return this.passwordExpiration;
}
public CapabilityUrls getCapabilityUrls() {
return this.capabilityUrls;
}
public String getSessionId() {
return this.sessionId;
}
public void setSessionId(String sessionId) {
this.sessionId = sessionId;
}
}

View File

@ -0,0 +1,9 @@
package com.ossez.usreio.client;
public class LogoutRequest extends VersionInsensitiveRequest {
@Override
public void setUrl(CapabilityUrls urls) {
setUrl(urls.getLogoutUrl());
}
}

View File

@ -0,0 +1,41 @@
package com.ossez.usreio.client;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
public class LogoutResponse extends KeyValueResponse {
private static final Log LOG = LogFactory.getLog(LogoutResponse.class);
private static final String CONNECT_TIME_KEY = "ConnectTime";
private static final String BILLING_KEY = "Billing";
private static final String SIGNOFF_KEY = "SignOffMessage";
private String seconds;
private String billingInfo;
private String logoutMessage;
@Override
protected void handleKeyValue(String key, String value) throws RetsException {
if (matchKey(key, CONNECT_TIME_KEY)) {
this.seconds = value;
} else if (matchKey(key, BILLING_KEY)) {
this.billingInfo = value;
} else if (matchKey(key, SIGNOFF_KEY)) {
this.logoutMessage = value;
} else {
assertStrictWarning(LOG, "Invalid logout response key: " + key + " -> " + value);
}
}
public String getSeconds() {
return this.seconds;
}
public String getBillingInfo() {
return this.billingInfo;
}
public String getLogoutMessage() {
return this.logoutMessage;
}
}

View File

@ -0,0 +1,61 @@
package com.ossez.usreio.client;
import com.ossez.usreio.tests.common.metadata.MetaCollector;
import com.ossez.usreio.tests.common.metadata.MetaObject;
import com.ossez.usreio.tests.common.metadata.MetadataType;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
public abstract class MetaCollectorAdapter implements MetaCollector {
public MetaObject[] getMetadata(MetadataType type, String path) {
return getSome(type, path, "0");
}
public MetaObject[] getMetadataRecursive(MetadataType type, String path) {
return getSome(type, path, "*");
}
private MetaObject[] getSome(MetadataType type, String path, String sfx) {
boolean compact = Boolean.getBoolean("rets-client.metadata.compact");
try {
GetMetadataRequest req;
if (path == null || path.equals("")) {
req = new GetMetadataRequest(type.name(), sfx);
} else {
String[] ppath = StringUtils.split(path, ":");
String[] id = new String[ppath.length + 1];
System.arraycopy(ppath, 0, id, 0, ppath.length);
id[ppath.length] = sfx;
req = new GetMetadataRequest(type.name(), id);
}
if (compact) {
req.setCompactFormat();
}
GetMetadataResponse response;
response = doRequest(req);
return response.getMetadata();
} catch (RetsException e) {
LOG.error("bad metadata request", e);
return null;
}
}
/**
* Perform operation of turning a GetMetadataRequest into
* a GetMetadataResponse
*
* @param req Requested metadata
* @return parsed MetaObjects
*
* @throws RetsException if an error occurs
*/
protected abstract GetMetadataResponse doRequest(GetMetadataRequest req) throws RetsException;
private static final Log LOG = LogFactory.getLog(MetaCollectorAdapter.class);
}

View File

@ -0,0 +1,22 @@
/*
* cart: CRT's Awesome RETS Tool
*
* Author: David Terrell
* Copyright (c) 2003, The National Association of REALTORS
* Distributed under a BSD-style license. See LICENSE.TXT for details.
*/
package com.ossez.usreio.client;
public class MetaCollectorImpl extends MetaCollectorAdapter {
private final RetsTransport mTransport;
public MetaCollectorImpl(RetsTransport transport) {
this.mTransport = transport;
}
@Override
protected GetMetadataResponse doRequest(GetMetadataRequest req) throws RetsException {
return this.mTransport.getMetadata(req);
}
}

View File

@ -0,0 +1,23 @@
package com.ossez.usreio.client;
/**
* A client can register a monitor for network events
*/
public interface NetworkEventMonitor
{
/**
* inform the client app that an event has started.
* the client app can return an object, which will be passed
* to eventFinish().
*
* @param message a message describing the event
* @return an object to be passed to eventFinish, or null
*/
public Object eventStart(String message);
/**
* Inform the client app that the previous event has completed
*
* @param o the object returned from eventStart
*/
public void eventFinish(Object o);
}

View File

@ -0,0 +1,13 @@
package com.ossez.usreio.client;
public class NullNetworkEventMonitor implements NetworkEventMonitor {
public Object eventStart(String message) {
return null;
}
public void eventFinish(Object o) {
//noop
}
}

View File

@ -0,0 +1,100 @@
package com.ossez.usreio.client;
import java.util.Map;
import java.util.HashMap;
public class ReplyCode {
// static initialization loop.... this declaration _MUST_ come before the members
private static final Map<Integer,ReplyCode> CODES = new HashMap<Integer,ReplyCode>();
public static final ReplyCode SUCCESS = new ReplyCode(0, "Success");
public static final ReplyCode ZERO_BALANCE = new ReplyCode(20003, "Zero balance");
public static final ReplyCode BROKER_CODE_REQUIRED = new ReplyCode(20012, "Broker code required");
public static final ReplyCode BROKER_CODE_INVALID = new ReplyCode(20013, "Broker Code Invalid");
public static final ReplyCode ADDTIONAL_LOGIN_NOT_PREMITTED = new ReplyCode(20022, "Additional login not permitted");
public static final ReplyCode MISCELLANEOUS_LOGIN_ERROR = new ReplyCode(20036, "Miscellaneous server login error");
public static final ReplyCode CLIENT_PASSWORD_INVALID = new ReplyCode(20037, "Client passsword invalid");
public static final ReplyCode SERVER_TEMPORARILY_DISABLED = new ReplyCode(20050, "Server temporarily disabled");
public static final ReplyCode UNKNOWN_QUERY_FIELD = new ReplyCode(20200, "Unknown Query Field");
public static final ReplyCode NO_RECORDS_FOUND = new ReplyCode(20201, "No Records Found");
public static final ReplyCode INVALID_SELECT = new ReplyCode(20202, "Invalid select");
public static final ReplyCode MISCELLANOUS_SEARCH_ERROR = new ReplyCode(20203, "Miscellaneous search error");
public static final ReplyCode INVALID_QUERY_SYNTAX = new ReplyCode(20206, "Invalid query syntax");
public static final ReplyCode UNAUTHORIZED_QUERY = new ReplyCode(20207, "Unauthorized query");
public static final ReplyCode MAXIMUM_RECORDS_EXCEEDED = new ReplyCode(20208, "Maximum records exceeded");
public static final ReplyCode SEARCH_TIMED_OUT = new ReplyCode(20209, "Search timed out");
public static final ReplyCode TOO_MANY_OUTSTANDING_QUERIES = new ReplyCode(20210, "Too many outstanding queries");
public static final ReplyCode INVALID_RESOURCE_GETOBJECT = new ReplyCode(20400, "Invalid Resource");
public static final ReplyCode INVALID_TYPE_GETOBJECT = new ReplyCode(20401, "Invalid Type");
public static final ReplyCode INVALID_IDENTIFIER_GETOBJECT = new ReplyCode(20402, "Invalid Identifier");
public static final ReplyCode NO_OBJECT_FOUND = new ReplyCode(20403, "No Object Found");
public static final ReplyCode UNSUPPORTED_MIME_TYPE_GETOBJECT = new ReplyCode(20406, "Unsupported MIME Type");
public static final ReplyCode UNAUTHORIZED_RETRIEVAL_GETOBJECT = new ReplyCode(20407, "Unauthorized Retrieval");
public static final ReplyCode RESOURCE_UNAVAILABLE_GETOBJECT = new ReplyCode(20408, "Resource Unavailable");
public static final ReplyCode OBJECT_UNAVAILABLE = new ReplyCode(20409, "Object Unavailable");
public static final ReplyCode REQUEST_TOO_LARGE_GETOBJECT = new ReplyCode(20410, "Request Too Large");
public static final ReplyCode TIMEOUT_GETOBJECT = new ReplyCode(20411, "Timeout");
public static final ReplyCode TOO_MANY_OUTSTANDING_QUERIES_GETOBJECT = new ReplyCode(20412,"Too Many Outstanding Queries");
public static final ReplyCode MISCELLANEOUS_ERROR_GETOBJECT = new ReplyCode(20413, "Miscellaneous Error");
public static final ReplyCode INVALID_RESOURCE = new ReplyCode(20500, "Invalid resource");
public static final ReplyCode INVALID_TYPE = new ReplyCode(20501, "Invalid type");
public static final ReplyCode INVALID_IDENTIFIER = new ReplyCode(20502, "Invalid identifier");
public static final ReplyCode NO_METADATA_FOUND = new ReplyCode(20503, "No metadata found");
public static final ReplyCode UNSUPPORTED_MIME_TYPE = new ReplyCode(20506, "Unsupported MIME type");
public static final ReplyCode UNAUTHORIZED_RETRIEVAL = new ReplyCode(20507, "Unauthorized retrieval");
public static final ReplyCode RESOURCE_UNAVAILABLE = new ReplyCode(20508, "Resource unavailable");
public static final ReplyCode METADATA_UNAVAILABLE = new ReplyCode(20509, "Metadata unavailable");
public static final ReplyCode REQUEST_TOO_LARGE = new ReplyCode(20510, "Request too large");
public static final ReplyCode TIMEOUT = new ReplyCode(20511, "Timeout");
public static final ReplyCode TOO_MANY_OUSTANDING_REQUESTS = new ReplyCode(20512, "Too many outstanding requests");
public static final ReplyCode MISCELLANEOUS_ERROR = new ReplyCode(20513, "Miscellanous error");
public static final ReplyCode REQUESTED_DTD_UNAVAILABLE = new ReplyCode(20514, "Requested DTD unvailable");
private final int mValue;
private final String mMessage;
private ReplyCode(int value, String message) {
this.mValue = value;
this.mMessage = message;
if (CODES.containsValue(new Integer(value)))
throw new IllegalArgumentException(String.format("value already used: %s ( %s ) ",value,message));
CODES.put(new Integer(value), this);
}
@Override
public boolean equals(Object o) {
if (!(o instanceof ReplyCode)) {
return false;
}
ReplyCode rhs = (ReplyCode) o;
return (this.mValue == rhs.mValue);
}
public boolean equals(int value) {
return this.mValue == value;
}
@Override
public String toString() {
return String.format("%s (%s)",this.mValue,this.mMessage);
}
public int getValue() {
return this.mValue;
}
public String getMessage() {
return this.mMessage;
}
public static ReplyCode fromValue(int value) {
ReplyCode replyCode = CODES.get(new Integer(value));
if (replyCode != null)
return replyCode;
return new ReplyCode(value, "Unknown");
}
}

View File

@ -0,0 +1,23 @@
package com.ossez.usreio.client;
/**
* @author jrayburn
*/
public interface ReplyCodeHandler {
/**
* ReplyCodeHandler can choose to handle reply codes
* that are non-zero reply codes in its own fashion.
*
* This is intended to be used to allow the SearchResultCollector
* to choose to throw InvalidReplyCodeException if the response is
* 20201 (Empty) or 20208 (MaxRowsExceeded).
*
* @param replyCode The RETS reply code
*
* @throws InvalidReplyCodeException Thrown if reply code is
* invalid for the SearchResultCollector.
*/
public void handleReplyCode(int replyCode) throws InvalidReplyCodeException;
}

View File

@ -0,0 +1,22 @@
package com.ossez.usreio.client;
/**
* @author YuCheng Hu
*/
public class RetsException extends Exception {
public RetsException() {
super();
}
public RetsException(String message) {
super(message);
}
public RetsException(String message, Throwable cause) {
super(message, cause);
}
public RetsException(Throwable cause) {
super(cause);
}
}

View File

@ -0,0 +1,36 @@
package com.ossez.usreio.client;
public abstract class RetsHttpClient {
public static final String SESSION_ID_COOKIE = "RETS-Session-ID";
public static final String LOGIN_SESSION_ID = "0";
public abstract void setUserCredentials(String userName, String password);
/**
* The protocol specific implementation happens here.
*
* @param httpMethod
* @param request
* @return
* @throws RetsException
*/
public abstract RetsHttpResponse doRequest(String httpMethod, RetsHttpRequest request) throws RetsException;
/**
*
*
* @param name header name, case should be preserved
* @param value static header value, if <tt>null</tt> then implementation should not include the header in requests
*/
/**
* Add an HTTP header that should be included by default in all requests
*
* @param name header name, case should be preserved
* @param value static header value, if <code>null</code> then implementation should not include the header in requests
*/
public abstract void addDefaultHeader(String name, String value);
}

View File

@ -0,0 +1,81 @@
package com.ossez.usreio.client;
import java.io.Serializable;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.SortedMap;
import java.util.TreeMap;
import com.ossez.usreio.common.util.CaseInsensitiveTreeMap;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.builder.ToStringBuilder;
/** Base Http Request object */
public abstract class RetsHttpRequest implements Serializable {
private final Map<String,String> mHeaders;
private final SortedMap<String,String> mQueryParameters;
protected String mUrl;
public RetsHttpRequest() {
this.mHeaders = new CaseInsensitiveTreeMap<String,String>();
this.mQueryParameters = new TreeMap<String,String>();
}
public abstract void setUrl(CapabilityUrls urls);
public void setUrl(String url) {
this.mUrl = url;
}
public String getUrl() {
return this.mUrl;
}
public void setHeader(String key, String value) {
this.mHeaders.put(key, value);
}
public Map<String,String> getHeaders() {
return this.mHeaders;
}
public String getHttpParameters() {
if (this.mQueryParameters.isEmpty())
return null;
List<String> params = new LinkedList<String>();
for(Map.Entry<String,String> param : this.mQueryParameters.entrySet()){
params.add(String.format("%s=%s",RetsUtil.urlEncode(param.getKey()),RetsUtil.urlEncode(param.getValue())));
}
return StringUtils.join(params.iterator(),"&");
}
protected void setQueryParameter(String name, String value) {
if (value == null) {
this.mQueryParameters.remove(name);
} else {
this.mQueryParameters.put(name, value);
}
}
@Override
public String toString() {
ToStringBuilder builder = new ToStringBuilder(this);
Iterator iterator = this.mQueryParameters.keySet().iterator();
while (iterator.hasNext()) {
String s = (String) iterator.next();
builder.append(s, this.mQueryParameters.get(s));
}
return builder.toString();
}
/**
* any request with version-specific handling should deal with this.
*
* @param version
*/
public abstract void setVersion(RetsVersion version);
}

View File

@ -0,0 +1,26 @@
package com.ossez.usreio.client;
import java.io.InputStream;
import java.util.Map;
/**
* Interface for retrieving useful header fields from a RETS HTTP response
*
* @author YuCheng Hu
*/
public interface RetsHttpResponse {
public int getResponseCode() throws RetsException;
public Map getHeaders() throws RetsException;
public String getHeader(String hdr) throws RetsException;
public String getCookie(String cookie) throws RetsException;
public String getCharset() throws RetsException;
public InputStream getInputStream() throws RetsException;
public Map getCookies() throws RetsException;
}

View File

@ -0,0 +1,403 @@
package com.ossez.usreio.client;
import java.util.Map;
import com.ossez.usreio.tests.common.metadata.Metadata;
import com.ossez.usreio.tests.common.metadata.MetadataException;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
/**
* RetsSession is the core class of the rets.client package.
*/
public class RetsSession {
public static final String METADATA_TABLES = "metadata_tables.xml";
public static final String RETS_CLIENT_VERSION = "1.5";//change default version
private static final Log LOG = LogFactory.getLog(RetsSession.class);
private static String sUserAgent = "crt-rets-client/" + RETS_CLIENT_VERSION;
private CapabilityUrls capabilityUrls;
private RetsHttpClient httpClient;
private RetsTransport transport;
private String sessionId;
/**
* Creates a new <code>RetsSession</code> instance.
* You must call login(user, pass) before attempting any other
* transactions.
*
* Uses a default implementation of RetsHttpClient based on
* apache commons http client.
*
* Uses the RetsVersion.RETS_DEFAULT as the RetsVersion for
* this session.
*
* Uses sAgent at the User-Agent setting for this RetsSession.
*
* @param loginUrl URL of the Login transaction.
*/
public RetsSession(String loginUrl) {
this(loginUrl, new CommonsHttpClient());
}
/**
* Creates a new <code>RetsSession</code> instance.
* You must call login(user, pass) before attempting any other
* transactions.
*
* Uses the RetsVersion.RETS_DEFAULT as the RetsVersion for
* this session.
*
* Uses sAgent at the User-Agent setting for this RetsSession.
*
* @param loginUrl URL of the Login transaction
* @param httpClient a RetsHttpClient implementation. The default
* is CommonsHttpClient.
*/
public RetsSession(String loginUrl, RetsHttpClient httpClient) {
this(loginUrl, httpClient, RetsVersion.DEFAULT);
}
/**
* Creates a new <code>RetsSession</code> instance.
* You must call login(user, pass) before attempting any other
* transactions.
*
* Uses sAgent at the User-Agent setting for this RetsSession.
*
* @param loginUrl URL of the Login transaction
* @param httpClient a RetsHttpClient implementation. The default
* is CommonsHttpClient.
* @param retsVersion The RetsVersion used by this RetsSession.
*/
public RetsSession(String loginUrl, RetsHttpClient httpClient, RetsVersion retsVersion) {
this(loginUrl, httpClient, retsVersion, sUserAgent,false);
}
/**
* Creates a new <code>RetsSession</code> instance.
* You must call login(user, pass) before attempting any other
* transactions.
*
* @param loginUrl URL of the Login transaction
* @param httpClient a RetsHttpClient implementation. The default
* is CommonsHttpClient.
* @param retsVersion The RetsVersion used by this RetsSession.
* @param userAgent specific User-Agent to use for this session.
*/
public RetsSession(String loginUrl, RetsHttpClient httpClient, RetsVersion retsVersion, String userAgent, boolean strict) {
this.capabilityUrls = new CapabilityUrls();
this.capabilityUrls.setLoginUrl(loginUrl);
this.httpClient = httpClient;
this.transport = new RetsTransport(httpClient, this.capabilityUrls, retsVersion, strict);
this.httpClient.addDefaultHeader("User-Agent", userAgent);
}
/**
* Query the current RetsVersion being used in this session.
*
* Initially, this will be the value passed to the RetsTransport.
* However, if during auto-negotiation the RetsTransport changes
* the RetsSession, this value may change throughout the session.
*
* @return the current RetsVersion value being used by the
* RetsTransport.
*/
public RetsVersion getRetsVersion() {
return this.transport.getRetsVersion();
}
/**
* Get the current RETS Session ID
*
* @return the current RETS Session ID or null is the server has
* not specified one
*/
public String getSessionId() {
return this.sessionId;
}
public void setSessionId(String sessionId) {
LOG.debug("setting Session-ID to: " + sessionId);
this.sessionId = sessionId;
}
public void setMonitor(NetworkEventMonitor monitor) {
this.transport.setMonitor(monitor);
}
public void setStrict(boolean strict) {
this.transport.setStrict(strict);
}
public boolean isStrict() {
return this.transport.isStrict();
}
/**
* Sets the default User-Agent value for RetsSessions created without
* a specified User-Agent value.
*
* @param userAgent Default User-Agent value to use for all RetsSession
* objects created in the future.
*/
public static void setUserAgent(String userAgent) {
sUserAgent = userAgent;
}
public String getLoginUrl() {
return this.capabilityUrls.getLoginUrl();
}
public Metadata getIncrementalMetadata() throws RetsException {
try {
return new Metadata(new MetaCollectorImpl(this.transport));
} catch (MetadataException e) {
throw new RetsException(e);
}
}
/**
* Get the complete RETS metadata.
*
* @return The RETS metadata object for these credentials.
*
* @throws RetsException
*/
public Metadata getMetadata() throws RetsException {
return this.transport.getMetadata("null");
}
/**
* Ability to download the raw metadata to a location
* @param location
* @return
* @throws RetsException
*/
public Metadata getMetadata(String location) throws RetsException {
return this.transport.getMetadata(location);
}
/**
* Perform a low level GetMetadatRequest. To retrieve
* structured metadata,
*
* @see #getMetadata()
*
* @param req GetMetadataRequest
* @return GetMetadataResponse, containing all MetaObjects
* returned
*
* @throws RetsException if an error occurs
*/
public GetMetadataResponse getMetadata(GetMetadataRequest req) throws RetsException {
return this.transport.getMetadata(req);
}
/**
* Fetches the action (MOTD) from the server.
*
* @exception RetsException if an error occurs
*/
private void getAction() throws RetsException {
String actionUrl = this.capabilityUrls.getActionUrl();
if (actionUrl == null) {
LOG.warn("No Action-URL available, skipping");
return;
}
GenericHttpRequest actionRequest = new GenericHttpRequest(actionUrl){
@Override
public Map<String, String> getHeaders() {
return null;
}
};
RetsHttpResponse httpResponse = this.httpClient.doRequest("GET", actionRequest);
try {
httpResponse.getInputStream().close();
} catch (Exception e) {
LOG.error("Action URL weirdness", e);
}
}
/**
* Implementation that allow for single or multi-part
* GetObject requests.
*
* @param req
* @return
* @exception RetsException if an error occurs
*/
public GetObjectResponse getObject(GetObjectRequest req) throws RetsException {
return this.transport.getObject(req);
}
/**
*
* @param resource
* @param type
* @param entity
* @param id
* @return response
* @exception RetsException if an error occurs
*/
public GetObjectResponse getObject(String resource, String type, String entity, String id) throws RetsException {
GetObjectRequest req = new GetObjectRequest(resource, type);
req.addObject(entity, id);
return getObject(req);
}
/**
* Log into the RETS server (see RETS 1.5, section 4). No other
* transactions will work until you have logged in.
*
* @param userName Username to authenticate
* @param password Password to authenticate with
* @return LoginResponse if success.
* @exception RetsException if authentication was denied
*/
public LoginResponse login(String userName, String password) throws RetsException {
return login(userName, password, null, null);
}
/**
* Log into the RETS server (see RETS 1.5, section 4). No other
* transactions will work until you have logged in.
*
* @param userName username to authenticate
* @param password password to authenticate with
* @param brokerCode broker code if the same user belongs to multiple
* brokerages. May be null.
* @param brokerBranch branch code if the same user belongs to multiple
* branches. May be null. brokerCode is required if you want
* brokerBranch to work.
* @return LoginResponse if success.
* @exception RetsException if authentication was denied
*/
public LoginResponse login(String userName, String password, String brokerCode, String brokerBranch) throws RetsException {
this.httpClient.setUserCredentials(userName, password);
LoginRequest request = new LoginRequest();
request.setBrokerCode(brokerCode, brokerBranch);
LoginResponse response = this.transport.login(request);
this.capabilityUrls = response.getCapabilityUrls();
this.transport.setCapabilities(this.capabilityUrls);
this.setSessionId(response.getSessionId());
this.getAction();
return response;
}
/**
* Log out of the current session. Another login _may_ re-establish a new connection
* depending the the behavior of the {#link RetsHttpClient} and its' ability to
* maintain and restablish a connection.
*
* @return a LogoutResponse
* @throws RetsException if the logout transaction failed
*/
public LogoutResponse logout() throws RetsException {
try {
return this.transport.logout();
} finally {
this.setSessionId(null);
}
}
/**
* Will perform a search as requested and return a filled
* SearchResult object. This method caches all result information
* in memory in the SearchResult object.
*
* @param req Contains parameters on which to search.
* @return a completed SearchResult
* @exception RetsException if an error occurs
*/
public SearchResult search(SearchRequest req) throws RetsException {
SearchResultImpl res = new SearchResultImpl();
search(req, res);
return res;
}
/**
* Execute a RETS Search. The collector object will be filled
* when this method is returned. See RETS 1.52d, Section 5.
*
* @param req Contains parameters on which to search.
* @param collector SearchResult object which will be informed of the results
* as they come in. If you don't need live results, see the other
* search invocation.
* @exception RetsException if an error occurs
*/
public void search(SearchRequest req, SearchResultCollector collector) throws RetsException {
this.transport.search(req, collector);
}
/**
* Search and process the Search using a given SearchResultProcessor.
*
* @param req the search request
* @param processor the result object that will process the data
*/
public SearchResultSet search(SearchRequest req, SearchResultProcessor processor) throws RetsException {
return this.transport.search(req, processor);
}
/**
* The lowest level integration. This method is not recommened for general use.
*/
public RetsHttpResponse request(RetsHttpRequest request) throws RetsException{
return this.transport.doRequest(request);
}
/**
* switch to a specific HttpMethodName, POST/GET, where the
* method is supported. Where GET is not supported, POST
* will be used.
* @param method the HttpMethodName to use
*/
public void setMethod(String method) {
this.transport.setMethod(method);
}
/** Make sure GC'd sessions are logged out. */
@Override
protected void finalize() throws Throwable {
try {
if( this.sessionId != null ) this.logout();
} finally {
super.finalize();
}
}
/**
* Performs a search returning only the number of records resulting from a query.
*
* Convenience method to get number records from a query
*
* @param req the search request
* @return the number of records that returned from the search request
* @throws RetsException
*/
public int getQueryCount(SearchRequest req) throws RetsException {
req.setCountOnly();
SearchResult res = this.search(req);
return res.getCount();
}
/**
* Gives the URL's of an Object request instead of object themselves
*
* Convenience method to get the URL's of the requeseted object only
*
* @param req
* @return
* @throws RetsException
*/
public GetObjectResponse getObjectUrl(GetObjectRequest req) throws RetsException {
req.setLocationOnly(true);
GetObjectResponse res = this.getObject(req);
return res;
}
}

View File

@ -0,0 +1,334 @@
package com.ossez.usreio.client;
import java.io.FileWriter;
import java.util.HashMap;
import java.util.Map;
import com.ossez.usreio.tests.common.metadata.JDomCompactBuilder;
import com.ossez.usreio.tests.common.metadata.JDomStandardBuilder;
import com.ossez.usreio.tests.common.metadata.Metadata;
import com.ossez.usreio.tests.common.metadata.MetadataBuilder;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.dom4j.Document;
import org.dom4j.io.SAXReader;
import org.dom4j.io.XMLWriter;
/**
* Implements the basic transport mechanism. This class deals with the
* very basic parts of sending the request, returning a response object,
* and version negotiation.
*
*/
public class RetsTransport {
private static final String RETS_SESSION_ID_HEADER = "RETS-Session-ID"; // TODO spec says hyphen, Marketlinx uses an underscore
private RetsHttpClient client;
private CapabilityUrls capabilities;
private String method = "GET";
private RetsVersion version;
private boolean strict;
private NetworkEventMonitor monitor;
private static final Log LOG = LogFactory.getLog(RetsTransport.class);
private static Map MONITOR_MSGS = new HashMap(){{
put(ChangePasswordRequest.class, "Transmitting change password request");
put(GetObjectRequest.class, "Retrieving media object");
put(LoginRequest.class, "Logging in");
put(GetMetadataRequest.class, "Retrieving metadata");
put(LogoutRequest.class, "Logging out");
put(SearchRequest.class, "Executing search");
}};
/**
* Create a new transport instance.
* @param client An http client (make sure you call setUserCredentials
* on it before carrying out any transactions).
* @param capabilities the initial capabilities url list. This can be
* replaced with a more up to date version at any time (for example,
* post-login()) with setCapabilities()
*
* @see RetsHttpClient#setUserCredentials
*/
public RetsTransport(RetsHttpClient client, CapabilityUrls capabilities) {
this(client, capabilities, RetsVersion.DEFAULT, false);
}
/**
* Create a new transport instance to speak a specific RETS version.
* @param client an http client
* @param capabilities the initial capabilities url list
* @param version the RETS version to use during initial negotiation
* (RetsTransport will automatically switch to whatever version the
* server supports).
*/
public RetsTransport(RetsHttpClient client, CapabilityUrls capabilities, RetsVersion version, boolean strict) {
this.client = client;
this.capabilities = capabilities;
this.doVersionHeader(version);
this.strict = strict;
this.client.addDefaultHeader("Accept", "*/*");
this.monitor = new NullNetworkEventMonitor();
}
/**
* Query the current RetsVersion being used in this RetsTransport.
*
* Initially, this will be the value with which this object was
* constructed.
*
* However, this value may change after login.
*
* @return the current RetsVersion value being used by the
* RetsTransport.
*/
public RetsVersion getRetsVersion() {
return this.version;
}
public boolean isStrict() {
return this.strict;
}
public void setStrict(boolean strict) {
this.strict = strict;
}
public void setMonitor(NetworkEventMonitor monitor) {
if (monitor == null) {
monitor = new NullNetworkEventMonitor();
}
this.monitor = monitor;
}
/**
* Set our RetsHttpClient up with the correct default RETS version to use,
* default to RETS 1.5.
* @param retsVersion
*/
private void doVersionHeader(RetsVersion retsVersion) {
if (this.client == null)
return;
if (retsVersion == null)
retsVersion = RetsVersion.DEFAULT;
this.version = retsVersion;
this.client.addDefaultHeader(RetsVersion.RETS_VERSION_HEADER, this.version.toString());
}
/**
* replace the capabilities url list with a new one
* @param capabilities the new capabilities url list
*/
public void setCapabilities(CapabilityUrls capabilities) {
this.capabilities = capabilities;
}
/**
* switch to a specific HttpMethodName, POST/GET, where the
* method is supported. Where GET is not supported, POST
* will be used.
* @param method the HttpMethodName to use
*/
public void setMethod(String method) {
this.method = method;
}
/**
* Available as an integration last resort
*/
public RetsHttpResponse doRequest(RetsHttpRequest req) throws RetsException {
Object monitorobj = null;
String msg = getMonitorMessage(req);
monitorobj = this.monitor.eventStart(msg);
req.setVersion(this.version);
req.setUrl(this.capabilities);
RetsHttpResponse httpResponse;
try {
httpResponse = this.client.doRequest(this.method, req);
} finally {
this.monitor.eventFinish(monitorobj);
}
return httpResponse;
}
private String getMonitorMessage(RetsHttpRequest req) {
String msg = (String) MONITOR_MSGS.get(req.getClass());
if (msg == null) {
msg = "communicating with network";
}
return msg;
}
/**
* Logs into the server. This transaction gets a list of capability URLs
* encapsulated in the LoginResponse that should typically be given back
* to the transport object with setCapabilities(). RETS Specification,
* section 4.
*
* @param req The login request
* @return the LoginResponse object
* @throws RetsException if the login failed or something went wrong on the
* network
* @see #setCapabilities
*/
public LoginResponse login(LoginRequest req) throws RetsException {
RetsHttpResponse retsHttpResponse = this.doRequest(req);
String versionHeader = retsHttpResponse.getHeader(RetsVersion.RETS_VERSION_HEADER);
// may be null, which is fine, return null, dont throw
RetsVersion retsVersion = RetsVersion.getVersion(versionHeader);
if( retsVersion == null && this.strict )
throw new RetsException(String.format("RETS Version is a required response header, version '%s' is unrecognized",versionHeader));
// skip updating the client version if its not set (correctly) by the server
if( retsVersion != null ) this.doVersionHeader(retsVersion);
LoginResponse response = new LoginResponse(this.capabilities.getLoginUrl());
String sessionId = retsHttpResponse.getCookie(RETS_SESSION_ID_HEADER);
response.setSessionId(sessionId);
response.setStrict(this.strict);
response.parse(retsHttpResponse.getInputStream(), this.version);
return response;
}
/**
* Logs out of the server. No other transactions should be called until
* another login() succeeds. RETS Specification, Section 6. Logout is
* an optional transaction. This method returns null if the server does
* not support the Logout transaction.
*
* @return LogoutResponse or null if logout is not supported
* @throws RetsException if there is a network or remote server error
*/
public LogoutResponse logout() throws RetsException {
if (this.capabilities.getLogoutUrl() == null) {
return null;
}
RetsHttpRequest req = new LogoutRequest();
RetsHttpResponse httpResponse = doRequest(req);
LogoutResponse response = new LogoutResponse();
response.setStrict(this.strict);
try {
response.parse(httpResponse.getInputStream(), this.version);
} catch(RetsException e) {
if (e.getMessage().contains("Invalid number of children")){// most RETS servers have issues logging out for some reason.
LOG.warn("unsual response for logout request, but log out successful.");
}
}
return response;
}
/**
* Perform a non-streaming search and pass all results from the
* SearchRequest to the given collector.
*
* 12/06/20 Added charset, needed for sax parser
* @param req the search request
* @param collector the result object that will store the data
*/
public void search(SearchRequest req, SearchResultCollector collector) throws RetsException {
RetsHttpResponse httpResponse = doRequest(req);
new SearchResultHandler(collector).parse(httpResponse.getInputStream(), httpResponse.getCharset());
}
/**
* Override processing of the search completely by providing a
* SearchResultProcessor to process the results of the Search.
*
* @param req the search request
* @param processor the result object that will process the data
*/
public SearchResultSet search(SearchRequest req, SearchResultProcessor processor) throws RetsException {
RetsHttpResponse httpResponse = doRequest(req);
return processor.parse(httpResponse.getInputStream());
}
/**
*
* @param req GetObject request
* @return a GetObjectResponse
* @throws RetsException if the request is not valid or a network error
* occurs
*/
public GetObjectResponse getObject(GetObjectRequest req) throws RetsException {
if (this.capabilities.getGetObjectUrl() == null) {
throw new RetsException("Server does not support GetObject transaction.");
}
req.setUrl(this.capabilities);
RetsHttpResponse httpResponse = this.client.doRequest(this.method, req);
GetObjectResponse result = new GetObjectResponse(httpResponse.getHeaders(), httpResponse.getInputStream());
return result;
}
public Metadata getMetadata(String location) throws RetsException {
boolean compact = Boolean.getBoolean("rets-client.metadata.compact");
GetMetadataRequest req = new GetMetadataRequest("SYSTEM", "*");
if (compact) {
req.setCompactFormat();
}
try {
RetsHttpResponse httpResponse = doRequest(req);
Object monitorobj = null;
monitorobj = this.monitor.eventStart("Parsing metadata");
try {
SAXReader xmlBuilder = new SAXReader();
Document xmlDocument = xmlBuilder.read(httpResponse.getInputStream());
if (!location.equals("null")){
FileWriter writer = new FileWriter(location);
XMLWriter outputter = new XMLWriter(writer);
outputter.write(xmlDocument);
outputter.close();
}
MetadataBuilder metadataBuilder;
if (req.isCompactFormat()) {
metadataBuilder = new JDomCompactBuilder();
} else {
metadataBuilder = new JDomStandardBuilder();
}
metadataBuilder.setStrict(this.strict);
return metadataBuilder.doBuild(xmlDocument);
} finally {
this.monitor.eventFinish(monitorobj);
}
} catch (Exception e) {
throw new RetsException(e);
}
}
public GetMetadataResponse getMetadata(GetMetadataRequest req) throws RetsException {
RetsHttpResponse httpResponse = doRequest(req);
Object monitorobj = null;
monitorobj = this.monitor.eventStart("Parsing metadata");
try {
try {
return new GetMetadataResponse(httpResponse.getInputStream(), req.isCompactFormat(),this.strict);
} catch (InvalidReplyCodeException e) {
e.setRequestInfo(req.toString());
throw e;
}
} finally {
this.monitor.eventFinish(monitorobj);
}
}
public boolean changePassword(ChangePasswordRequest req) throws RetsException {
RetsHttpResponse httpResponse = doRequest(req);
ChangePasswordResponse response = new ChangePasswordResponse(httpResponse.getInputStream());
// response will throw an exception if there is an error code
return (response != null);
}
}

View File

@ -0,0 +1,48 @@
package com.ossez.usreio.client;
import org.apache.commons.codec.DecoderException;
import org.apache.commons.codec.EncoderException;
import org.apache.commons.codec.net.URLCodec;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
/**
* Random utility functions
*
* @author YuCheng Hu
*/
public class RetsUtil {
public static void copyStream(InputStream in, OutputStream out) throws IOException {
byte[] buf = new byte[512];
int count;
while (true) {
count = in.read(buf);
if (count < 1) {
in.close();
out.close();
return;
}
while (count > 0) {
out.write(buf);
}
}
}
public static String urlEncode(String string) {
try {
return new URLCodec().encode(string);
} catch (EncoderException e) {
throw new RuntimeException(e);
}
}
public static String urlDecode(String string) {
try {
return new URLCodec().decode(string);
} catch (DecoderException e) {
throw new RuntimeException(e);
}
}
}

View File

@ -0,0 +1,106 @@
package com.ossez.usreio.client;
import java.io.Serializable;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.math.NumberUtils;
/**
* RetsVersion
*
* @author YuCheng Hu
*/
public class RetsVersion implements Serializable {
public static final String RETS_VERSION_HEADER = "RETS-Version";
public static final RetsVersion RETS_10 = new RetsVersion(1, 0, 0, 0);
public static final RetsVersion RETS_15 = new RetsVersion(1, 5, 0, 0);
public static final RetsVersion RETS_16 = new RetsVersion(1, 6, 0, 0);
public static final RetsVersion RETS_17 = new RetsVersion(1, 7, 0, 0);
public static final RetsVersion RETS_1_7_2 = new RetsVersion(1, 7, 2, 0);
public static final RetsVersion RETS_1_8 = new RetsVersion(1, 8, 0, 0);
public static final RetsVersion RETS_1_9 = new RetsVersion(1, 9, 0, 0);
public static final RetsVersion DEFAULT = RETS_1_7_2;
private int mMajor;
private int mMinor;
private int mRevision;
private int mDraft;
public RetsVersion(int major, int minor) {
this(major, minor, 0, 0);
}
/**
* @deprecated use <code>new RetsVersion(major, minor, 0, draft)</code>
*/
@Deprecated
public RetsVersion(int major, int minor, int draft) {
this(major, minor, 0, draft);
}
public RetsVersion(int major, int minor, int revision, int draft) {
this.mMajor = major;
this.mMinor = minor;
this.mRevision = revision;
this.mDraft = draft;
}
public int getMajor() {
return this.mMajor;
}
public int getMinor() {
return this.mMinor;
}
public int getRevision() {
return this.mRevision;
}
public int getDraft() {
return this.mDraft;
}
@Override
public String toString() {
if (this.mRevision == 0) {
if (this.mDraft == 0) {
return "RETS/" + this.mMajor + "." + this.mMinor;
}
return "RETS/" + this.mMajor + "." + this.mMinor + "d" + this.mDraft;
}
if (this.mDraft == 0) {
return "RETS/" + this.mMajor + "." + this.mMinor + "." + this.mRevision;
}
return "RETS/" + this.mMajor + "." + this.mMinor + "." + this.mRevision + "d" + this.mDraft;
}
@Override
public boolean equals(Object o) {
if (o instanceof RetsVersion) {
RetsVersion v = (RetsVersion) o;
if ((v.getMajor() == this.mMajor) && (v.getMinor() == this.mMinor) && (v.getRevision() == this.mRevision) && (v.getDraft() == this.mDraft)) {
return true;
}
}
return false;
}
public static RetsVersion getVersion(String ver) {
if (StringUtils.isEmpty(ver)) return null;
String[] split = StringUtils.trimToEmpty(ver).split("\\.");
int ma = NumberUtils.toInt(split[0], 1);
int mn = split.length > 1 ? NumberUtils.toInt(split[1], 0) : 0;
int re = 0;
int dr = 0;
if (split.length > 2) {
split = StringUtils.defaultString(split[2]).split("d");
re = NumberUtils.toInt(split[0], 0);
dr = split.length > 1 ? NumberUtils.toInt(split[1], 0) : 0;
}
return new RetsVersion(ma, mn, re, dr);
}
}

View File

@ -0,0 +1,122 @@
package com.ossez.usreio.client;
/**
*
* The search request sent from search() in RetsSession
*
*/
public class SearchRequest extends RetsHttpRequest {
public static final int COUNT_NONE = 1;
public static final int COUNT_FIRST = 2;
public static final int COUNT_ONLY = 3;
public static final String FORMAT_STANDARD_XML = "STANDARD-XML";
public static final String FORMAT_COMPACT = "COMPACT";
public static final String FORMAT_COMPACT_DECODED = "COMPACT-DECODED";
public static final String RETS_DMQL1 = "DMQL";
public static final String RETS_DMQL2 = "DMQL2";
public static final String KEY_TYPE = "SearchType";
public static final String KEY_CLASS = "Class";
public static final String KEY_DMQLVERSION = "QueryType";
public static final String KEY_QUERY = "Query";
public static final String KEY_COUNT = "Count";
public static final String KEY_FORMAT = "Format";
public static final String KEY_LIMIT = "Limit";
public static final String KEY_OFFSET = "Offset";
public static final String KEY_SELECT = "Select";
public static final String KEY_RESTRICTEDINDICATOR = "RestrictedIndicator";
public static final String KEY_STANDARDNAMES = "StandardNames";
private String type;
public SearchRequest(String stype, String sclass, String query) {
setQueryParameter(KEY_TYPE, stype);
this.type = stype;
setQueryParameter(KEY_CLASS, sclass);
setQueryParameter(KEY_QUERY, query);
setQueryParameter(KEY_FORMAT, FORMAT_COMPACT);
setQueryParameter(KEY_DMQLVERSION, RETS_DMQL2);
}
@Override
public void setUrl(CapabilityUrls urls) {
setUrl(urls.getSearchUrl());
}
public String getType() {
return this.type;
}
public void setCountNone() {
setQueryParameter(KEY_COUNT, null);
}
public void setCountFirst() {
setQueryParameter(KEY_COUNT, "1");
}
public void setCountOnly() {
setQueryParameter(KEY_COUNT, "2");
}
public void setFormatCompact() {
setQueryParameter(KEY_FORMAT, FORMAT_COMPACT);
}
public void setFormatCompactDecoded() {
setQueryParameter(KEY_FORMAT, FORMAT_COMPACT_DECODED);
}
public void setFormatStandardXml() {
setQueryParameter(KEY_FORMAT, FORMAT_STANDARD_XML);
}
public void setFormatStandardXml(String dtdVersion) {
setQueryParameter(KEY_FORMAT, FORMAT_STANDARD_XML + ":" + dtdVersion);
}
public void setLimit(int count) {
setQueryParameter(KEY_LIMIT, Integer.toString(count));
}
public void setLimitNone() {
setQueryParameter(KEY_LIMIT, null);
}
public void setSelect(String sel) {
setQueryParameter(KEY_SELECT, sel);
}
public void setRestrictedIndicator(String rest) {
setQueryParameter(KEY_RESTRICTEDINDICATOR, rest);
}
public void setStandardNames() {
setQueryParameter(KEY_STANDARDNAMES, "1");
}
public void setSystemNames() {
setQueryParameter(KEY_STANDARDNAMES, null);
}
public void setOffset(int offset) {
setQueryParameter(KEY_OFFSET, Integer.toString(offset));
}
public void setOffsetNone() {
setQueryParameter(KEY_OFFSET, null);
}
/** TODO should the search automatically handle this??? shouldn't this be setable by vendor is that predicatable? */
@Override
public void setVersion(RetsVersion ver) {
if (RetsVersion.RETS_10.equals(ver)) {
setQueryParameter(KEY_DMQLVERSION, RETS_DMQL1);
} else {
setQueryParameter(KEY_DMQLVERSION, RETS_DMQL2);
}
}
}

View File

@ -0,0 +1,23 @@
package com.ossez.usreio.client;
import java.util.NoSuchElementException;
import java.util.Iterator;
/**
* Interface for retrieving additional information from of a result from a RETS query/search
*
*/
public interface SearchResult extends SearchResultInfo {
public String[] getRow(int idx) throws NoSuchElementException;
public Iterator iterator();
public String[] getColumns();
public boolean isMaxrows();
public int getCount();
public boolean isComplete();
}

View File

@ -0,0 +1,18 @@
package com.ossez.usreio.client;
/**
* Interface for a setting properties of a result from a query (used by SearchResultHandler)
*/
public interface SearchResultCollector {
public void setCount(int count);
public void setColumns(String[] columns);
public boolean addRow(String[] row);
public void setMaxrows();
public void setComplete();
}

View File

@ -0,0 +1,280 @@
package com.ossez.usreio.client;
import java.io.IOException;
import java.io.InputStream;
import java.util.LinkedList;
import java.util.List;
import java.util.StringTokenizer;
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.xml.sax.Attributes;
import org.xml.sax.ContentHandler;
import org.xml.sax.ErrorHandler;
import org.xml.sax.InputSource;
import org.xml.sax.Locator;
import org.xml.sax.SAXException;
import org.xml.sax.SAXParseException;
import org.xml.sax.XMLReader;
/**
*
* Handles XML parsing from response setting the proper fields using a SearchResultCollector
*
*/
public class SearchResultHandler implements ContentHandler, ErrorHandler{
private static final Log LOG = LogFactory.getLog(SearchResultHandler.class);
private static SAXParserFactory FACTORY = SAXParserFactory.newInstance();
private int dataCount;
private SearchResultCollector collector;
private StringBuffer currentEntry;
private String delimiter;
private Locator locator;
private String[] columns;
private InvalidReplyCodeHandler invalidReplyCodeHandler;
private CompactRowPolicy compactRowPolicy;
public SearchResultHandler(SearchResultCollector r) {
this(r, InvalidReplyCodeHandler.FAIL, CompactRowPolicy.DEFAULT);
}
public SearchResultHandler(SearchResultCollector r, InvalidReplyCodeHandler invalidReplyCodeHandler, CompactRowPolicy badRowPolicy) {
this.compactRowPolicy = badRowPolicy;
if (r == null)
throw new NullPointerException("SearchResultCollector must not be null");
if (invalidReplyCodeHandler == null)
throw new NullPointerException("InvalidReplyCodeHandler must not be null");
if (badRowPolicy == null)
throw new NullPointerException("BadRowPolicy must not be null");
this.collector = r;
this.dataCount = 0;
this.invalidReplyCodeHandler = invalidReplyCodeHandler;
}
public void startElement(String uri, String localName, String qName, Attributes atts) throws SAXException {
String name = localName;
if (localName.equals("")) {
name = qName;
}
if (name.equals("RETS") || name.equals("RETS-STATUS")) {
String rawrepcode = atts.getValue("ReplyCode");
try {
int repcode = Integer.parseInt(rawrepcode);
if (repcode > 0) {
try {
if (ReplyCode.MAXIMUM_RECORDS_EXCEEDED.equals(repcode))
return;
if (ReplyCode.NO_RECORDS_FOUND.equals(repcode))
return;
if (name.equals("RETS"))
this.invalidReplyCodeHandler.invalidRetsReplyCode(repcode);
else
this.invalidReplyCodeHandler.invalidRetsStatusReplyCode(repcode);
} catch (InvalidReplyCodeException e) {
String text = atts.getValue("", "ReplyText");
e.setRemoteMessage(text);
throw new SAXException(e);
}
}
} catch (NumberFormatException e) {
throw new SAXParseException("Invalid ReplyCode '" + rawrepcode + "'", this.locator);
}
return;
}
if (name == "COUNT") {
String s = atts.getValue("Records");
if (s == null) {
s = atts.getValue("", "Records");
if (s == null) {
throw new SAXParseException("COUNT tag has no Records " + "attribute", this.locator);
}
}
int i = Integer.parseInt(s, 10);
this.collector.setCount(i);
return;
}
if (name == "DELIMITER") {
String s = atts.getValue("value");
if (s == null) {
s = atts.getValue("", "value");
if (s == null) {
throw new RuntimeException("Invalid Delimiter");
}
}
int i = Integer.parseInt(s, 16);
this.delimiter = "" + (char) i;
return;
}
if (name == "COLUMNS" || name == "DATA") {
this.currentEntry = new StringBuffer();
return;
}
if (name == "MAXROWS") {
this.collector.setMaxrows();
return;
}
// Unknown tag. danger, will.
LOG.warn("Unknown tag: " + name + ", qName = " + qName);
}
public void characters(char[] ch, int start, int length) {
if (this.currentEntry != null) {
this.currentEntry.append(ch, start, length);
}
}
public void ignorableWhitespace(char[] ch, int start, int length) {
// we ignore NOZINK!
characters(ch, start, length);
}
/** do NOT use string.split() unless your prepared to deal with loss due to token boundary conditions */
private String[] split(String input) throws SAXParseException {
if (this.delimiter == null) {
throw new SAXParseException("Invalid compact format - DELIMITER not specified", this.locator);
}
if( !input.startsWith(this.delimiter) ){
throw new SAXParseException("Invalid compact format", this.locator);
}
StringTokenizer tkn = new StringTokenizer(input, this.delimiter, true);
List list = new LinkedList();
tkn.nextToken(); // junk the first element
String last = null;
while (tkn.hasMoreTokens()) {
String next = tkn.nextToken();
if (next.equals(this.delimiter)) {
if (last == null) {
list.add("");
} else {
last = null;
}
} else {
list.add(next);
last = next;
}
}
return (String[]) list.toArray(new String[0]);
}
public void endElement(String uri, String localName, String qName) throws SAXParseException {
String name = localName;
if (name.equals("")) {
name = qName;
}
if (name.equals("COLUMNS") || name.equals("DATA")) {
String[] contents = split(this.currentEntry.toString());
if (name.equals("COLUMNS")) {
this.collector.setColumns(contents);
this.columns = contents;
} else {
if( this.compactRowPolicy.apply(this.dataCount, this.columns, contents) ) {
this.dataCount++;
this.collector.addRow(contents);
}
}
this.currentEntry = null;
}
}
public void startDocument() {
LOG.info("Start document");
}
public void endDocument() {
LOG.info("Document ended");
this.collector.setComplete();
}
public void startPrefixMapping(String prefix, String uri) throws SAXException {
// LOG.debug("prefix mapping: " + prefix);
}
public void endPrefixMapping(String prefix) throws SAXException {
// LOG.debug("prefix mapping: " + prefix);
}
public void processingInstruction(String target, String data) throws SAXException {
throw new SAXException("processing instructions not supported: " + "target=" + target + ", data=" + data);
}
public void skippedEntity(String name) throws SAXException {
throw new SAXException("skipped entities not supported: name=" + name);
}
public void setDocumentLocator(Locator locator) {
this.locator = locator;
}
public void error(SAXParseException e) throws SAXException {
throw e;
}
public void fatalError(SAXParseException e) throws SAXException {
throw e;
}
public void warning(SAXParseException e) {
LOG.warn("an error occured while parsing. Attempting to continue", e);
}
public void parse(InputSource src) throws RetsException {
parse(src, null);
}
/**
*
* created in order to pass the charset to the parser for proper encoding
* @param str
* @param charset
* @throws RetsException
*/
public void parse(InputStream str, String charset) throws RetsException {
parse(new InputSource(str), charset);
try {
str.close();
} catch (IOException e) {
throw new RetsException(e);
}
}
/**
* Pareses given source with the given charset
*
* @param src
* @throws RetsException
*/
public void parse(InputSource src, String charset) throws RetsException {
String encoding = src.getEncoding();
if (encoding == null && (charset != null)){
encoding = charset;
LOG.warn("Charset from headers:" + charset + ". Setting as correct encoding for parsing");
src.setEncoding(encoding);
}
try {
SAXParser p = FACTORY.newSAXParser();
XMLReader r = p.getXMLReader();
r.setContentHandler(this);
r.setErrorHandler(this);
r.parse(src);
} catch (SAXException se) {
if (se.getException() != null && se.getException() instanceof RetsException) {
throw (RetsException) se.getException();
}
throw new RetsException(se);
} catch (Exception e) {
LOG.error("An exception occured", e);
throw new RetsException(e);
}
}
}

View File

@ -0,0 +1,87 @@
package com.ossez.usreio.client;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.NoSuchElementException;
import org.apache.commons.logging.LogFactory;
/**
* Concrete Implementation of SearchResult interface
*
*/
public class SearchResultImpl implements SearchResult, SearchResultCollector {
private String[] columnNames;
private int count;
private List<String[]> rows;
private boolean maxRows;
private boolean complete;
public SearchResultImpl() {
this.count = 0;
this.rows = new ArrayList<String[]>();
this.maxRows = false;
this.complete = false;
}
public void setCount(int count) {
this.count = count;
}
public int getCount() {
if (this.count > 0) {
return this.count;
}
return this.rows.size();
}
public int getRowCount() {
return this.rows.size();
}
public void setColumns(String[] columns) {
this.columnNames = columns;
}
public String[] getColumns() {
return this.columnNames;
}
public boolean addRow(String[] row) {
if (row.length > this.columnNames.length) {
throw new IllegalArgumentException(String.format("Invalid number of result columns: got %s, expected %s",row.length, this.columnNames.length));
}
if (row.length < this.columnNames.length) {
LogFactory.getLog(SearchResultCollector.class).warn(String.format("Row %s: Invalid number of result columns: got %s, expected ",this.rows.size(), row.length, this.columnNames.length));
}
return this.rows.add(row);
}
public String[] getRow(int idx) {
if (idx >= this.rows.size()) {
throw new NoSuchElementException();
}
return this.rows.get(idx);
}
public Iterator iterator() {
return this.rows.iterator();
}
public void setMaxrows() {
this.maxRows = true;
}
public boolean isMaxrows() {
return this.maxRows;
}
public void setComplete() {
this.complete = true;
}
public boolean isComplete() {
return this.complete;
}
}

View File

@ -0,0 +1,25 @@
package com.ossez.usreio.client;
/**
* Interface that describes high level information
* about the results of a search.
* @author jrayburn
*/
public interface SearchResultInfo {
public int getCount() throws RetsException;
public String[] getColumns() throws RetsException;
/** @throws IllegalStateException */
public boolean isMaxrows() throws RetsException, IllegalStateException;
/**
* Indicates that processing of this search
* is complete.
*
* @return true if this SearchResultSet is finished processing.
* @throws RetsException Thrown if there is an error
* processing the SearchResultSet.
*/
public boolean isComplete() throws RetsException;
}

View File

@ -0,0 +1,13 @@
package com.ossez.usreio.client;
import java.io.InputStream;
import java.io.Reader;
/**
* Interface for parsing results from a RETS query/search
*/
public interface SearchResultProcessor {
public SearchResultSet parse(InputStream in) throws RetsException;
public SearchResultSet parse(Reader in) throws RetsException;
}

View File

@ -0,0 +1,15 @@
package com.ossez.usreio.client;
/**
* Iterator style interface for processing the results
* of a RETS search a single time. Information about the
* search can be retrieved once processing is complete by
* calling the getInfo() method.
*
* @author YuCheng Hu
*/
public interface SearchResultSet extends SearchResultInfo {
public String[] next() throws RetsException;
public boolean hasNext() throws RetsException;
}

View File

@ -0,0 +1,53 @@
package com.ossez.usreio.client;
import com.ossez.usreio.common.util.CaseInsensitiveTreeMap;
import java.io.InputStream;
import java.util.Map;
/**
* Representation of a single object returned
* from a RETS server.
*
* @author jrayburn
*/
public class SingleObjectResponse {
public static final String CONTENT_TYPE = "Content-Type";
public static final String LOCATION = "Location";
public static final String CONTENT_DESCRIPTION = "Content-Description";
public static final String OBJECT_ID = "Object-ID";
public static final String CONTENT_ID = "Content-ID";
private Map headers;
private InputStream inputStream;
public SingleObjectResponse(Map headers, InputStream in) {
this.headers = new CaseInsensitiveTreeMap(headers);
this.inputStream = in;
}
public String getType() {
return (String) this.headers.get(CONTENT_TYPE);
}
public String getContentID() {
return (String) this.headers.get(CONTENT_ID);
}
public String getObjectID() {
return (String) this.headers.get(OBJECT_ID);
}
public String getDescription() {
return (String) this.headers.get(CONTENT_DESCRIPTION);
}
public String getLocation() {
return (String) this.headers.get(LOCATION);
}
public InputStream getInputStream() {
return this.inputStream;
}
}

View File

@ -0,0 +1,64 @@
package com.ossez.usreio.client;
import java.io.FilterInputStream;
import java.io.IOException;
import java.io.PushbackInputStream;
class SinglePartInputStream extends FilterInputStream {
private static final int EOS = -1;
private final String boundary;
private boolean eos;
SinglePartInputStream(PushbackInputStream partInput, String boundary) {
super(partInput);
this.boundary = boundary;
}
@Override
public int read() throws IOException {
int read = this.getPushBackStream().read();
// was this the start of a boundary?
if( read != '\r' && read != '\n' ) return read;
this.getPushBackStream().unread(read);
byte[] peek = new byte[ "\r\n".length() + this.boundary.length()];
// if so, check and see if the rest of the boundary is next
int peekRead = this.getPushBackStream().read(peek);
this.getPushBackStream().unread(peek, 0, peekRead);
if( new String(peek).contains(this.boundary) ) return EOS;
// if not, just a coincidence, just return the byte
return this.getPushBackStream().read();
}
@Override
public int read(byte[] b, int off, int len) throws IOException {
if(this.eos) return EOS;
int read = off;
for( ; read < off + len; read++) {
int nextByte = this.read();
if(nextByte == EOS) {
this.eos = true;
break;
}
b[read] = (byte) nextByte;
}
return ( read - off );
}
@Override
public int read(byte[] b) throws IOException {
return this.read(b, 0, b.length);
}
@Override
public void close() {
// noop - part of a larger stream
}
private PushbackInputStream getPushBackStream() {
return (PushbackInputStream) this.in;
}
}

View File

@ -0,0 +1,324 @@
package com.ossez.usreio.client;
import java.io.InputStream;
import java.io.Reader;
import java.util.LinkedList;
import org.apache.commons.logging.LogFactory;
import org.xml.sax.InputSource;
/**
* SearchResultProcessor that returns a streaming SearchResult implementation.
*
* @author jrayburn
*/
public class StreamingSearchResultProcessor implements SearchResultProcessor {
private final int mBufferSize;
private final int mTimeout;
private InvalidReplyCodeHandler mInvalidReplyCodeHandler;
private CompactRowPolicy mCompactRowPolicy;
/**
* Construct a StreamingSearchResultProcessor.
*
* Waits indefinitely for buffer to be read from by
* client.
*
* @param bufferSize
* How many rows to buffer
*/
public StreamingSearchResultProcessor(int bufferSize) {
this(bufferSize, 0);
}
/**
* Construct a StreamingSearchResultProcessor.
*
* Waits <code>timeout</code> milliseconds for buffer to
* be read from by client.
*
* @param bufferSize
* How many rows to buffer
*
* @param timeout
* How long to wait, in milliseconds, for the buffer
* to be read from when full. 0 indicates an indefinite
* wait.
*/
public StreamingSearchResultProcessor(int bufferSize, int timeout) {
super();
this.mBufferSize = bufferSize;
this.mTimeout = timeout;
}
/** how to deal with badly delimited data */
public void setCompactRowPolicy(CompactRowPolicy badRowPolicy) {
this.mCompactRowPolicy = badRowPolicy;
}
private CompactRowPolicy getCompactRowPolicy() {
if (this.mCompactRowPolicy == null)
return CompactRowPolicy.DEFAULT;
return this.mCompactRowPolicy;
}
public void setInvalidRelyCodeHandler(InvalidReplyCodeHandler invalidReplyCodeHandler) {
this.mInvalidReplyCodeHandler = invalidReplyCodeHandler;
}
private InvalidReplyCodeHandler getInvalidRelyCodeHandler() {
if (this.mInvalidReplyCodeHandler == null)
return InvalidReplyCodeHandler.FAIL;
return this.mInvalidReplyCodeHandler;
}
public SearchResultSet parse(InputStream reader) {
return parse(new InputSource(reader));
}
public SearchResultSet parse(Reader reader) {
return parse(new InputSource(reader));
}
public SearchResultSet parse(InputSource source) {
StreamingSearchResult result = new StreamingSearchResult(this.mBufferSize, this.mTimeout);
StreamingThread thread = new StreamingThread(source, result, this.getInvalidRelyCodeHandler(), this.getCompactRowPolicy());
thread.start();
return result;
}
}
class StreamingThread extends Thread {
private StreamingSearchResult mResult;
private InputSource mSource;
private InvalidReplyCodeHandler mInvalidReplyCodeHandler;
private CompactRowPolicy badRowPolicy;
public StreamingThread(InputSource source, StreamingSearchResult result,InvalidReplyCodeHandler invalidReplyCodeHandler, CompactRowPolicy badRowPolicy) {
this.mSource = source;
this.mResult = result;
this.mInvalidReplyCodeHandler = invalidReplyCodeHandler;
this.badRowPolicy = badRowPolicy;
}
@Override
public void run() {
SearchResultHandler handler = new SearchResultHandler(this.mResult, this.mInvalidReplyCodeHandler, this.badRowPolicy);
try {
handler.parse(this.mSource);
} catch (RetsException e) {
this.mResult.setException(e);
} catch (Exception e) {
// socket timeouts, etc while obtaining xml bytes from InputSource ...
this.mResult.setException(new RetsException("Low level exception while attempting to parse input from source.", e));
}
}
}
class StreamingSearchResult implements SearchResultSet, SearchResultCollector {
private static final int PREPROCESS = 0;
private static final int BUFFER_AVAILABLE = 1;
private static final int BUFFER_FULL = 2;
private static final int COMPLETE = 3;
private final int timeout;
private final int bufferSize;
private final LinkedList<String[]> buffer;
private boolean mMaxrows;
private int state;
private String[] columns;
private int count;
private RetsException exception;
public StreamingSearchResult(int bufferSize, int timeout) {
if (bufferSize < 1)
throw new IllegalArgumentException("[bufferSize=" + bufferSize + "] must be greater than zero");
if (timeout < 0)
throw new IllegalArgumentException("[timeout=" + timeout + "] must be greater than or equal to zero");
this.bufferSize = bufferSize;
this.timeout = timeout;
this.state = PREPROCESS;
this.buffer = new LinkedList<String[]>();
this.count = -1;
this.columns = null;
this.exception = null;
}
// ------------ Producer Methods
public synchronized boolean addRow(String[] row) {
if (row.length > this.columns.length) {
throw new IllegalArgumentException(String.format("Invalid number of result columns: got %s, expected %s",row.length, this.columns.length));
}
if (row.length < this.columns.length) {
LogFactory.getLog(SearchResultCollector.class).warn(String.format("Row %s: Invalid number of result columns: got %s, expected ",this.count, row.length, this.columns.length));
}
if (state() > BUFFER_FULL) {
if (this.exception == null)
setException(new RetsException("Attempting to add rows to buffer when in complete state"));
throw new RuntimeException(this.exception);
}
// check complete.
while (checkRuntime() && state() == BUFFER_FULL) {
_wait();
if (state() >= BUFFER_FULL) {
if (this.exception == null)
setException(new RetsException("Timeout writing to streaming result set buffer, timeout length = "
+ this.timeout));
throw new RuntimeException(this.exception);
}
}
this.buffer.addLast(row);
if (this.bufferSize == this.buffer.size())
pushState(BUFFER_FULL);
else
pushState(BUFFER_AVAILABLE);
this.notifyAll();
return true;
}
public synchronized void setComplete() {
pushState(COMPLETE);
notifyAll();
}
public synchronized void setCount(int count) {
this.count = count;
pushState(PREPROCESS);
notifyAll();
}
public synchronized void setColumns(String[] columns) {
this.columns = columns;
pushState(BUFFER_AVAILABLE);
notifyAll();
}
public synchronized void setMaxrows() {
this.mMaxrows = true;
pushState(COMPLETE);
notifyAll();
}
synchronized void setException(RetsException e) {
this.exception = e;
pushState(COMPLETE);
notifyAll();
}
// ----------- Consumer Methods
public synchronized boolean hasNext() throws RetsException {
// wait for someone to add data to the queue
// or flag complete
while (checkException() && state() < COMPLETE) {
if (!this.buffer.isEmpty())
return true;
_wait();
}
return !this.buffer.isEmpty();
}
public synchronized String[] next() throws RetsException {
checkException();
String[] row = this.buffer.removeFirst();
if (this.state < COMPLETE)
pushState(BUFFER_AVAILABLE);
this.notifyAll();
return row;
}
public synchronized int getCount() throws RetsException {
while (checkException() && state() < BUFFER_AVAILABLE) {
_wait();
}
return this.count;
}
public synchronized String[] getColumns() throws RetsException {
while (checkException() && state() < BUFFER_AVAILABLE) {
_wait();
}
return this.columns;
}
public synchronized boolean isMaxrows() throws RetsException {
checkException();
if (!isComplete())
throw new IllegalStateException("Cannot call isMaxRows until isComplete == true");
return this.mMaxrows;
}
public synchronized SearchResultInfo getInfo() throws RetsException {
checkException();
if (!isComplete())
throw new IllegalStateException("Cannot call isMaxRows until isComplete == true");
return this;
}
public synchronized boolean isComplete() throws RetsException {
checkException();
return state() >= COMPLETE;
}
private synchronized boolean checkRuntime() {
try {
return checkException();
} catch (RetsException e) {
throw new RuntimeException(e);
}
}
private synchronized boolean checkException() throws RetsException {
// considering doing something here to maintain the original
// stack trace but also provide the stack trace from this
// location...
if (this.exception != null)
throw this.exception;
return true;
}
private void _wait() {
try {
wait(this.timeout);
} catch (InterruptedException e) {
pushState(COMPLETE);
throw new RuntimeException(e);
}
}
private void pushState(int newState) {
if (this.state >= COMPLETE && newState < COMPLETE)
throw new IllegalStateException("Cannot revert from complete state");
if (this.state > PREPROCESS && newState <= PREPROCESS)
throw new IllegalStateException("Cannot revert to preprocess state");
if (newState < this.state && newState != BUFFER_AVAILABLE && this.state != BUFFER_FULL)
throw new IllegalStateException("Cannot go back in state unless reverting to buffer available from full");
this.state = newState;
}
private int state() {
return this.state;
}
}

View File

@ -0,0 +1,15 @@
package com.ossez.usreio.client;
public abstract class VersionInsensitiveRequest extends RetsHttpRequest {
/**
* Abstract class of subclasses where the Version of RETS is not needed (Password Request, Login Request, etc.)
*/
public VersionInsensitiveRequest() {
super();
}
@Override
public void setVersion(RetsVersion version) {
//noop - I don't care about version
}
}

View File

@ -0,0 +1,126 @@
package com.ossez.usreio.client.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</code>
* 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,35 @@
package com.ossez.usreio.client.retsapi;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* RETSActionTransaction.java
*
* This class is used to build an action transaction
*
* @author jbrush
* @version 1.0
*/
public class RETSActionTransaction extends RETSTransaction {
private final static Logger logger = LoggerFactory.getLogger(RETSActionTransaction.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 com.ossez.usreio.client.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,176 @@
package com.ossez.usreio.client.retsapi;
import com.ossez.usreio.common.util.DesCrypter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.security.MessageDigest;
/**
* Send a Change Password transaction to the server.
*
* @author jbrush
* @version 1.0
*/
public class RETSChangePasswordTransaction extends RETSTransaction {
private final static Logger logger = LoggerFactory.getLogger(RETSActionTransaction.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"));
logger.debug("username=" + username);
logger.debug("oldPassword=" + oldPassword);
logger.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) {
logger.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,635 @@
/*
* RETSConnection.java
*
* Created on November 16, 2001, 1:33 PM
*/
package com.ossez.usreio.client.retsapi;
//import com.aftexsw.util.bzip.CBZip2InputStream;
import com.ossez.usreio.common.util.RETSConfigurator;
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.slf4j.Logger;
import org.slf4j.LoggerFactory;
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 {
private final static Logger logger = LoggerFactory.getLogger(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 transaction transaction to execute
*/
public void execute(RETSTransaction transaction) {
execute(transaction, false);
}
/**
* Executes a transaction
*
* @param transaction transaction to execute
*/
public void executeStreamResponse(RETSTransaction transaction) {
execute(transaction, true);
}
/**
* Executes a transaction
*
* @param transaction transaction to execute
* @param asStream
*/
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) {
logger.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();
}
}
logger.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;
logger.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();
logger.debug(transaction.getRequestType() + " URL : {" + serverUrl + "}");
if (serverUrl == null) {
logger.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";
}
logger.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) {
logger.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));
logger.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,51 @@
/**
* RETSGetMetadataTransaction.java
*
* @author jbrush
* @version
*/
package com.ossez.usreio.client.retsapi;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
///////////////////////////////////////////////////////////////////////
public class RETSGetMetadataTransaction extends RETSTransaction {
private final static Logger logger = LoggerFactory.getLogger(RETSConnection.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,339 @@
package com.ossez.usreio.client.retsapi;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.mail.MessagingException;
import javax.mail.internet.InternetHeaders;
import javax.mail.internet.MimeBodyPart;
import javax.mail.internet.MimeMultipart;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
/**
* RETSGetObjectTransaction.java
*
* @author jbrush
* @version 1.0
*/
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}.
*/
private final static Logger logger = LoggerFactory.getLogger(RETSLoginTransaction.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) {
logger.debug("set Resource=" + str);
setRequestVariable("Resource", str);
}
/**
* Sets the type attribute to the string passed in.
*
* @param str type attribute value
*/
public void setType(String str) {
logger.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) {
logger.debug("set ID=" + str.trim());
setRequestVariable("ID", str.trim());
} else {
logger.debug("set ID=" + str);
}
}
/**
* Sets the location attribute to the string passed in.
*
* @param str location attribute value
*/
public void setLocation(String str) {
logger.debug("set Location=" + str);
setRequestVariable("Location", str);
}
/**
* Sets the response stream. This triggers various actions depending on the
* content-type of the response stream:
* <p>
* 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.
* <p>
* 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.
* <p>
* 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.
* 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");
logger.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) {
logger.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();
logger.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.
logger.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.
* 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
*/
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)
logger.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.
*/
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.
* <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;
logger.debug("--- MimeBodyPart Content--> " + content);
}
} catch (Exception e) {
e.printStackTrace();
throw new RuntimeException("Kablewie!");
}
return inputStream;
}
}

View File

@ -0,0 +1,184 @@
package com.ossez.usreio.client.retsapi;
//import org.apache.regexp.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
/**
* RETSLoginTransaction.java
*
*
* @author jbrush
* @version 1.0
*/
public class RETSLoginTransaction extends RETSTransaction {
/** log4j Object */
private final static Logger logger = LoggerFactory.getLogger(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.
* @return 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);
logger.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();
logger.debug("protocol = [" + protocol + "]");
logger.debug("host = [" + host + "]");
logger.debug("port = [" + port + "]");
//cat.debug("path = ["+path+"]");
//cat.debug("file = ["+file+"]");
return protocol + "://" + host + ((port > 0) ? (":" + port) : "");
} catch (MalformedURLException e) {
logger.warn("getUrlRoot:MalformedURLException myUrl=\"" + myUrl +
"\"");
}
return null;
}
}

View File

@ -0,0 +1,32 @@
package com.ossez.usreio.client.retsapi;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Send a logout transaction to the server.
*
* @author jbrush
* @version 1.0
*/
public class RETSLogoutTransaction extends RETSTransaction {
private final static Logger logger = LoggerFactory.getLogger(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,32 @@
package com.ossez.usreio.client.retsapi;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* RETSSearchAgentTransaction.java
* Search for agents
*
* @author jbrush
* @version 1.0
*/
public class RETSSearchAgentTransaction extends RETSSearchTransaction {
private final static Logger logger = LoggerFactory.getLogger(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,27 @@
package com.ossez.usreio.client.retsapi;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* RETSSearchOfficeTransaction.java
* Performs a getOffice Transaction
*
* @author jbrush
* @version 1.0
*/
public class RETSSearchOfficeTransaction extends RETSSearchTransaction {
private final static Logger logger = LoggerFactory.getLogger(RETSSearchOfficeTransaction.class);
/** Creates new a RETSSearchOfficeTransaction
*
*/
public RETSSearchOfficeTransaction() {
super();
setSearchType("Office");
setSearchClass("Office");
// setSearchClass("OFF");
}
}

View File

@ -0,0 +1,26 @@
package com.ossez.usreio.client.retsapi;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* RETSSearchPropertyBatchTransaction.java
*
* @author jbrush
* @version 1.0
*/
public class RETSSearchPropertyBatchTransaction extends RETSSearchTransaction {
private final static Logger logger = LoggerFactory.getLogger(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,20 @@
package com.ossez.usreio.client.retsapi;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* RETSSearchPropertyBatchTransaction.java
*
* @author jbrush
* @version 1.0
*/
public class RETSSearchPropertyTransaction extends RETSSearchTransaction {
private final static Logger logger = LoggerFactory.getLogger(RETSSearchPropertyTransaction.class);
public RETSSearchPropertyTransaction() {
super();
setSearchType("Property");
}
}

View File

@ -0,0 +1,321 @@
package com.ossez.usreio.client.retsapi;
import com.ossez.usreio.common.util.AttributeExtracter;
import com.ossez.usreio.common.util.ResourceLocator;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.xml.sax.helpers.DefaultHandler;
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;
import java.io.ByteArrayInputStream;
import java.util.HashMap;
/**
* RETSSearchTransaction
*
* @author YuCheng Hu
*/
public class RETSSearchTransaction extends RETSTransaction {
private final static Logger logger = LoggerFactory.getLogger(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) {
logger.warn("Hash Error:", 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,50 @@
/**
* RETSServerInformationTransaction.java
*
* @author pobrien
* @version
*/
package com.ossez.usreio.client.retsapi;
//import java.util.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
///////////////////////////////////////////////////////////////////////
public class RETSServerInformationTransaction extends RETSTransaction {
private final static Logger logger = LoggerFactory.getLogger(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,277 @@
/**
* RETSTransaction.java
*
* @author jbrush
* @version
*/
package com.ossez.usreio.client.retsapi;
import com.ossez.usreio.common.util.RETSRequestResponse;
import org.apache.regexp.RE;
import org.apache.regexp.RESyntaxException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.StringTokenizer;
///////////////////////////////////////////////////////////////////////
public class RETSTransaction extends RETSRequestResponse {
private final static Logger logger = LoggerFactory.getLogger(RETSConnection.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) {
logger.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());
logger.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) {
logger.debug("RESPONSEHEADERMAP ==> " + responseHeaderMap.toString());
// responseString = (String) responseHeaderMap.get(headerName.toLowerCase());
logger.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 {
logger.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) {
logger.debug(logMessage);
}
}

View File

@ -0,0 +1,156 @@
package com.ossez.usreio.client.retsapi;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.Iterator;
import java.util.Map;
/**
* RETSUpdateTransaction.java
*
* @author pobrien
* @version 1.0
*/
public class RETSUpdateTransaction extends RETSTransaction {
private final static Logger logger = LoggerFactory.getLogger(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 str type attribute value
*/
public void setType(String str) {
logger.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) {
logger.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) {
logger.debug("set Delimiter=" + str);
setRequestVariable("Delimiter", str);
}
public String getDelimiter() {
return getRequestVariable("Delimiter");
}
public void setRecord(String str) {
logger.debug("set Record=" + str);
setRequestVariable("Record", str);
}
public void setWarningResponse(String str) {
logger.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);
}
}

View File

@ -0,0 +1,16 @@
/*
* cart: CRT's Awesome RETS Tool
*
* Author: David Terrell
* Copyright (c) 2003, The National Association of REALTORS
* Distributed under a BSD-style license. See LICENSE.TXT for details.
*/
package com.ossez.usreio.tests.common.metadata;
import java.io.Serializable;
public interface AttrType<T> extends Serializable {
public T parse(String value, boolean strict) throws MetaParseException;
public Class<T> getType();
public String render(T value);
}

View File

@ -0,0 +1,702 @@
/*
* cart: CRT's Awesome RETS Tool
*
* Author: David Terrell
* Copyright (c) 2003, The National Association of REALTORS
* Distributed under a BSD-style license. See LICENSE.TXT for details.
*/
package com.ossez.usreio.tests.common.metadata;
import java.util.LinkedList;
import java.util.List;
import java.util.StringTokenizer;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.dom4j.*;
import com.ossez.usreio.tests.common.metadata.types.MClass;
import com.ossez.usreio.tests.common.metadata.types.MEditMask;
import com.ossez.usreio.tests.common.metadata.types.MLookup;
import com.ossez.usreio.tests.common.metadata.types.MLookupType;
import com.ossez.usreio.tests.common.metadata.types.MObject;
import com.ossez.usreio.tests.common.metadata.types.MResource;
import com.ossez.usreio.tests.common.metadata.types.MSearchHelp;
import com.ossez.usreio.tests.common.metadata.types.MSystem;
import com.ossez.usreio.tests.common.metadata.types.MTable;
import com.ossez.usreio.tests.common.metadata.types.MUpdate;
import com.ossez.usreio.tests.common.metadata.types.MUpdateType;
import com.ossez.usreio.tests.common.metadata.types.MValidationExpression;
import com.ossez.usreio.tests.common.metadata.types.MValidationExternal;
import com.ossez.usreio.tests.common.metadata.types.MValidationExternalType;
import com.ossez.usreio.tests.common.metadata.types.MValidationLookup;
import com.ossez.usreio.tests.common.metadata.types.MValidationLookupType;
import org.dom4j.io.SAXReader;
import org.xml.sax.InputSource;
public class JDomCompactBuilder extends MetadataBuilder {
public static final String CONTAINER_PREFIX = "METADATA-";
public static final String CONTAINER_ROOT = "RETS";
public static final String CONTAINER_METADATA = "METADATA";
public static final String CONTAINER_SYSTEM = "METADATA-SYSTEM";
public static final String CONTAINER_RESOURCE = "METADATA-RESOURCE";
public static final String CONTAINER_FOREIGNKEY = "METADATA-FOREIGN_KEY";
public static final String CONTAINER_CLASS = "METADATA-CLASS";
public static final String CONTAINER_TABLE = "METADATA-TABLE";
public static final String CONTAINER_UPDATE = "METADATA-UPDATE";
public static final String CONTAINER_UPDATETYPE = "METADATA-UPDATE_TYPE";
public static final String CONTAINER_OBJECT = "METADATA-OBJECT";
public static final String CONTAINER_SEARCHHELP = "METADATA-SEARCH_HELP";
public static final String CONTAINER_EDITMASK = "METADATA-EDITMASK";
public static final String CONTAINER_UPDATEHELP = "METADATA-UPDATE_HELP";
public static final String CONTAINER_LOOKUP = "METADATA-LOOKUP";
public static final String CONTAINER_LOOKUPTYPE = "METADATA-LOOKUP_TYPE";
public static final String CONTAINER_VALIDATIONLOOKUP = "METADATA-VALIDATION_LOOKUP";
public static final String CONTAINER_VALIDATIONLOOKUPTYPE = "METADATA-VALIDATION_LOOKUP_TYPE";
public static final String CONTAINER_VALIDATIONEXPRESSION = "METADATA-VALIDATION_EXPRESSION";
public static final String CONTAINER_VALIDATIONEXTERNAL = "METADATA-VALIDATION_EXTERNAL";
public static final String CONTAINER_VALIDATIONEXTERNALTYPE = "METADATA-VALIDATION_EXTERNAL_TYPE";
public static final String ELEMENT_SYSTEM = "SYSTEM";
public static final String COLUMNS = "COLUMNS";
public static final String DATA = "DATA";
public static final String ATTRIBUTE_RESOURCE = "Resource";
public static final String ATTRIBUTE_CLASS = "Class";
public static final String ATTRIBUTE_UPDATE = "Update";
public static final String ATTRIBUTE_LOOKUP = "Lookup";
public static final String ATTRIBUTE_VALIDATIONEXTERNAL = "ValidationExternal";
public static final String ATTRIBUTE_VALIDATIONLOOKUP = "ValidationLookup";
private static final Log LOG = LogFactory.getLog(JDomCompactBuilder.class);
@Override
public Metadata doBuild(Object src) throws MetadataException {
return build((Document) src);
}
public Metadata build(InputSource source) throws MetadataException {
SAXReader builder = new SAXReader();
Document document;
try {
document = builder.read(source);
} catch (DocumentException e) {
throw new MetadataException("Couldn't build document", e);
}
return build(document);
}
@Override
public MetaObject[] parse(Object src) throws MetadataException {
return parse((Document) src);
}
public MetaObject[] parse(Document src) throws MetadataException {
Element root = src.getRootElement();
if (!root.getName().equals(CONTAINER_ROOT)) {
throw new MetadataException("Invalid root element");
}
Element container = root.element(CONTAINER_SYSTEM);
if (container != null) {
MSystem sys = processSystem(container);
if (root.element(CONTAINER_RESOURCE) != null) {
Metadata m = new Metadata(sys);
recurseAll(m, root);
}
return new MetaObject[] { sys };
}
container = root.element(CONTAINER_RESOURCE);
if (container != null) {
return processResource(container);
}
container = root.element(CONTAINER_CLASS);
if (container != null) {
return processClass(container);
}
container = root.element(CONTAINER_TABLE);
if (container != null) {
return processTable(container);
}
container = root.element(CONTAINER_UPDATE);
if (container != null) {
return processUpdate(container);
}
container = root.element(CONTAINER_UPDATETYPE);
if (container != null) {
return processUpdateType(container);
}
container = root.element(CONTAINER_OBJECT);
if (container != null) {
return processObject(container);
}
container = root.element(CONTAINER_SEARCHHELP);
if (container != null) {
return processSearchHelp(container);
}
container = root.element(CONTAINER_EDITMASK);
if (container != null) {
return processEditMask(container);
}
container = root.element(CONTAINER_LOOKUP);
if (container != null) {
return processLookup(container);
}
container = root.element(CONTAINER_LOOKUPTYPE);
if (container != null) {
return processLookupType(container);
}
container = root.element(CONTAINER_VALIDATIONLOOKUP);
if (container != null) {
return processValidationLookup(container);
}
container = root.element(CONTAINER_VALIDATIONLOOKUPTYPE);
if (container != null) {
return processValidationLookupType(container);
}
container = root.element(CONTAINER_VALIDATIONEXTERNAL);
if (container != null) {
return processValidationExternal(container);
}
container = root.element(CONTAINER_VALIDATIONEXTERNALTYPE);
if (container != null) {
return processValidationExternalType(container);
}
container = root.element(CONTAINER_VALIDATIONEXPRESSION);
if (container != null) {
return processValidationExpression(container);
}
return null;
}
public Metadata build(Document src) throws MetadataException {
Element root = src.getRootElement();
if (!root.getName().equals(CONTAINER_ROOT)) {
throw new MetadataException("Invalid root element");
}
Element element = root.element(CONTAINER_SYSTEM);
if (element == null) {
throw new MetadataException("Missing element " + CONTAINER_SYSTEM);
}
MSystem sys = processSystem(element);
Metadata metadata;
metadata = new Metadata(sys);
recurseAll(metadata, root);
return metadata;
}
private void recurseAll(Metadata metadata, Element root) throws MetaParseException {
attachResource(metadata, root);
attachClass(metadata, root);
attachTable(metadata, root);
attachUpdate(metadata, root);
attachUpdateType(metadata, root);
attachObject(metadata, root);
attachSearchHelp(metadata, root);
attachEditMask(metadata, root);
attachLookup(metadata, root);
attachLookupType(metadata, root);
attachValidationLookup(metadata, root);
attachValidationLookupType(metadata, root);
attachValidationExternal(metadata, root);
attachValidationExternalType(metadata, root);
attachValidationExpression(metadata, root);
}
private void setAttributes(MetaObject obj, String[] columns, String[] data) {
int count = columns.length;
if (count > data.length) {
count = data.length;
}
for (int i = 0; i < count; i++) {
String column = columns[i];
String datum = data[i];
if (!datum.equals("")) {
setAttribute(obj, column, datum);
}
}
}
private String[] getColumns(Element el) {
Element cols = el.element(COLUMNS);
return split(cols);
}
/** do NOT use string.split() unless your prepared to deal with loss due to token boundary conditions */
private String[] split(Element el) {
if( el == null ) return null;
final String delimiter = "\t";
StringTokenizer tkn = new StringTokenizer(el.getText(), delimiter, true);
List list = new LinkedList();
tkn.nextToken(); // junk the first element
String last = null;
while (tkn.hasMoreTokens()) {
String next = tkn.nextToken();
if (next.equals(delimiter)) {
if (last == null) {
list.add("");
} else {
last = null;
}
} else {
list.add(next);
last = next;
}
}
return (String[]) list.toArray(new String[0]);
}
/**
* Gets an attribute that is not expected to be null (i.e. an attribute that
* MUST exist).
*
* @param element Element
* @param name Attribute name
* @return value of attribute
* @throws MetaParseException if the value is null.
*/
private String getNonNullAttribute(Element element, String name) throws MetaParseException {
String value = element.attributeValue(name);
if (value == null) {
throw new MetaParseException("Attribute '" + name + "' not found on tag " + toString(element));
}
return value;
}
private String toString(Element element) {
StringBuffer buffer = new StringBuffer();
List attributes = element.attributes();
buffer.append("'").append(element.getName()).append("'");
buffer.append(", attributes: ").append(attributes);
return buffer.toString();
}
private MSystem processSystem(Element container) {
Element element = container.element(ELEMENT_SYSTEM);
MSystem system = buildSystem();
// system metadata is such a hack. the first one here is by far my favorite
String comment = container.elementText(MSystem.COMMENTS);
String systemId = element.attributeValue(MSystem.SYSTEMID);
String systemDescription = element.attributeValue(MSystem.SYSTEMDESCRIPTION);
String version = container.attributeValue(MSystem.VERSION);
String date = container.attributeValue(MSystem.DATE);
setAttribute(system, MSystem.COMMENTS, comment);
setAttribute(system, MSystem.SYSTEMID, systemId);
setAttribute(system, MSystem.SYSTEMDESCRIPTION, systemDescription);
setAttribute(system, MSystem.VERSION, version);
setAttribute(system, MSystem.DATE, date);
return system;
}
private void attachResource(Metadata metadata, Element root) {
MSystem system = metadata.getSystem();
List containers = root.elements(CONTAINER_RESOURCE);
for (int i = 0; i < containers.size(); i++) {
Element container = (Element) containers.get(i);
MResource[] resources = this.processResource(container);
for (int j = 0; j < resources.length; j++) {
system.addChild(MetadataType.RESOURCE, resources[j]);
}
}
}
private MResource[] processResource(Element resourceContainer) {
String[] columns = getColumns(resourceContainer);
List rows = resourceContainer.elements(DATA);
MResource[] resources = new MResource[rows.size()];
for (int i = 0; i < rows.size(); i++) {
Element element = (Element) rows.get(i);
String[] data = split(element);
MResource resource = buildResource();
setAttributes(resource, columns, data);
resources[i] = resource;
}
return resources;
}
private void attachClass(Metadata metadata, Element root) throws MetaParseException {
List containers = root.elements(CONTAINER_CLASS);
for (int i = 0; i < containers.size(); i++) {
Element container = (Element) containers.get(i);
String resourceId = getNonNullAttribute(container, ATTRIBUTE_RESOURCE);
MResource resource = metadata.getResource(resourceId);
MClass[] classes = processClass(container);
for (int j = 0; j < classes.length; j++) {
resource.addChild(MetadataType.CLASS, classes[j]);
}
}
}
private MClass[] processClass(Element classContainer) throws MetaParseException {
String name = classContainer.getName();
String resourceId = getNonNullAttribute(classContainer, ATTRIBUTE_RESOURCE);
LOG.debug("resource name: " + resourceId + " for container " + name);
String[] columns = getColumns(classContainer);
List rows = classContainer.elements(DATA);
MClass[] classes = new MClass[rows.size()];
for (int i = 0; i < rows.size(); i++) {
Element element = (Element) rows.get(i);
String[] data = split(element);
MClass clazz = buildClass();
setAttributes(clazz, columns, data);
classes[i] = clazz;
}
return classes;
}
private void attachTable(Metadata metadata, Element root) throws MetaParseException {
List containers = root.elements(CONTAINER_TABLE);
for (int i = 0; i < containers.size(); i++) {
Element container = (Element) containers.get(i);
String resourceId = getNonNullAttribute(container, ATTRIBUTE_RESOURCE);
String className = getNonNullAttribute(container, ATTRIBUTE_CLASS);
MClass clazz = metadata.getMClass(resourceId, className);
if (clazz == null) {
//MarketLinx Strikes!!!
LOG.warn("Found table metadata for resource class: " + resourceId + ":" + className
+ " but there is no class metadata for " + resourceId + ":" + className);
continue;
}
MTable[] fieldMetadata = processTable(container);
for (int j = 0; j < fieldMetadata.length; j++) {
clazz.addChild(MetadataType.TABLE, fieldMetadata[j]);
}
}
}
private MTable[] processTable(Element tableContainer) {
String[] columns = getColumns(tableContainer);
List rows = tableContainer.elements(DATA);
MTable[] fieldMetadata = new MTable[rows.size()];
for (int i = 0; i < rows.size(); i++) {
Element element = (Element) rows.get(i);
String[] data = split(element);
MTable mTable = buildTable();
setAttributes(mTable, columns, data);
fieldMetadata[i] = mTable;
}
return fieldMetadata;
}
private void attachUpdate(Metadata metadata, Element root) throws MetaParseException {
List containers = root.elements(CONTAINER_UPDATE);
for (int i = 0; i < containers.size(); i++) {
Element container = (Element) containers.get(i);
MClass parent = metadata.getMClass(getNonNullAttribute(container, ATTRIBUTE_RESOURCE), getNonNullAttribute(
container, ATTRIBUTE_CLASS));
MUpdate[] updates = processUpdate(container);
for (int j = 0; j < updates.length; j++) {
parent.addChild(MetadataType.UPDATE, updates[j]);
}
}
}
private MUpdate[] processUpdate(Element container) {
String[] columns = getColumns(container);
List rows = container.elements(DATA);
MUpdate[] updates = new MUpdate[rows.size()];
for (int i = 0; i < rows.size(); i++) {
Element element = (Element) rows.get(i);
String[] data = split(element);
MUpdate update = buildUpdate();
setAttributes(update, columns, data);
updates[i] = update;
}
return updates;
}
private void attachUpdateType(Metadata metadata, Element root) throws MetaParseException {
List containers = root.elements(CONTAINER_UPDATETYPE);
for (int i = 0; i < containers.size(); i++) {
Element container = (Element) containers.get(i);
MUpdate parent = metadata.getUpdate(getNonNullAttribute(container, ATTRIBUTE_RESOURCE),
getNonNullAttribute(container, ATTRIBUTE_CLASS), getNonNullAttribute(container, ATTRIBUTE_UPDATE));
MUpdateType[] updateTypes = processUpdateType(container);
for (int j = 0; j < updateTypes.length; j++) {
parent.addChild(MetadataType.UPDATE_TYPE, updateTypes[j]);
}
}
}
private MUpdateType[] processUpdateType(Element container) {
String[] columns = getColumns(container);
List rows = container.elements(DATA);
MUpdateType[] updateTypes = new MUpdateType[rows.size()];
for (int i = 0; i < rows.size(); i++) {
Element element = (Element) rows.get(i);
String[] data = split(element);
MUpdateType updateType = buildUpdateType();
setAttributes(updateType, columns, data);
updateTypes[i] = updateType;
}
return updateTypes;
}
private void attachObject(Metadata metadata, Element root) throws MetaParseException {
List containers = root.elements(CONTAINER_OBJECT);
for (int i = 0; i < containers.size(); i++) {
Element container = (Element) containers.get(i);
MResource parent = metadata.getResource(getNonNullAttribute(container, ATTRIBUTE_RESOURCE));
MObject[] objects = processObject(container);
for (int j = 0; j < objects.length; j++) {
parent.addChild(MetadataType.OBJECT, objects[j]);
}
}
}
private MObject[] processObject(Element objectContainer) {
String[] columns = getColumns(objectContainer);
List rows = objectContainer.elements(DATA);
MObject[] objects = new MObject[rows.size()];
for (int i = 0; i < rows.size(); i++) {
Element element = (Element) rows.get(i);
String[] data = split(element);
MObject object = buildObject();
setAttributes(object, columns, data);
objects[i] = object;
}
return objects;
}
private void attachSearchHelp(Metadata metadata, Element root) throws MetaParseException {
List containers = root.elements(CONTAINER_SEARCHHELP);
for (int i = 0; i < containers.size(); i++) {
Element container = (Element) containers.get(i);
MResource parent = metadata.getResource(getNonNullAttribute(container, ATTRIBUTE_RESOURCE));
MSearchHelp[] searchHelps = processSearchHelp(container);
for (int j = 0; j < searchHelps.length; j++) {
parent.addChild(MetadataType.SEARCH_HELP, searchHelps[j]);
}
}
}
private MSearchHelp[] processSearchHelp(Element container) {
String[] columns = getColumns(container);
List rows = container.elements(DATA);
MSearchHelp[] searchHelps = new MSearchHelp[rows.size()];
for (int i = 0; i < rows.size(); i++) {
Element element = (Element) rows.get(i);
String[] data = split(element);
MSearchHelp searchHelp = buildSearchHelp();
setAttributes(searchHelp, columns, data);
searchHelps[i] = searchHelp;
}
return searchHelps;
}
private void attachEditMask(Metadata metadata, Element root) throws MetaParseException {
List containers = root.elements(CONTAINER_EDITMASK);
for (int i = 0; i < containers.size(); i++) {
Element container = (Element) containers.get(i);
MResource parent = metadata.getResource(getNonNullAttribute(container, ATTRIBUTE_RESOURCE));
MEditMask[] editMasks = processEditMask(container);
for (int j = 0; j < editMasks.length; j++) {
parent.addChild(MetadataType.EDITMASK, editMasks[j]);
}
}
}
private MEditMask[] processEditMask(Element container) {
String[] columns = getColumns(container);
List rows = container.elements(DATA);
MEditMask[] editMasks = new MEditMask[rows.size()];
for (int i = 0; i < rows.size(); i++) {
Element element = (Element) rows.get(i);
String[] data = split(element);
MEditMask editMask = buildEditMask();
setAttributes(editMask, columns, data);
editMasks[i] = editMask;
}
return editMasks;
}
private void attachLookup(Metadata metadata, Element root) throws MetaParseException {
List containers = root.elements(CONTAINER_LOOKUP);
for (int i = 0; i < containers.size(); i++) {
Element container = (Element) containers.get(i);
MResource parent = metadata.getResource(getNonNullAttribute(container, ATTRIBUTE_RESOURCE));
MLookup[] lookups = processLookup(container);
for (int j = 0; j < lookups.length; j++) {
parent.addChild(MetadataType.LOOKUP, lookups[j]);
}
}
}
private MLookup[] processLookup(Element container) {
String[] columns = getColumns(container);
List rows = container.elements(DATA);
MLookup[] lookups = new MLookup[rows.size()];
for (int i = 0; i < rows.size(); i++) {
Element element = (Element) rows.get(i);
String[] data = split(element);
MLookup lookup = buildLookup();
setAttributes(lookup, columns, data);
lookups[i] = lookup;
}
return lookups;
}
private void attachLookupType(Metadata metadata, Element root) throws MetaParseException {
List containers = root.elements(CONTAINER_LOOKUPTYPE);
for (int i = 0; i < containers.size(); i++) {
Element container = (Element) containers.get(i);
MLookup parent = metadata.getLookup(getNonNullAttribute(container, ATTRIBUTE_RESOURCE),
getNonNullAttribute(container, ATTRIBUTE_LOOKUP));
if (parent == null) {
LOG.warn("Skipping lookup type: could not find lookup for tag " + toString(container));
continue;
}
MLookupType[] lookupTypes = processLookupType(container);
for (int j = 0; j < lookupTypes.length; j++) {
parent.addChild(MetadataType.LOOKUP_TYPE, lookupTypes[j]);
}
}
}
private MLookupType[] processLookupType(Element container) {
String[] columns = getColumns(container);
List rows = container.elements(DATA);
MLookupType[] lookupTypes = new MLookupType[rows.size()];
for (int i = 0; i < rows.size(); i++) {
Element element = (Element) rows.get(i);
String[] data = split(element);
MLookupType lookupType = buildLookupType();
setAttributes(lookupType, columns, data);
lookupTypes[i] = lookupType;
}
return lookupTypes;
}
private void attachValidationLookup(Metadata metadata, Element root) throws MetaParseException {
List containers = root.elements(CONTAINER_VALIDATIONLOOKUP);
for (int i = 0; i < containers.size(); i++) {
Element container = (Element) containers.get(i);
MResource parent = metadata.getResource(getNonNullAttribute(container, ATTRIBUTE_RESOURCE));
MValidationLookup[] validationLookups = processValidationLookup(container);
for (int j = 0; j < validationLookups.length; j++) {
parent.addChild(MetadataType.VALIDATION_LOOKUP, validationLookups[j]);
}
}
}
private MValidationLookup[] processValidationLookup(Element container) {
String[] columns = getColumns(container);
List rows = container.elements(DATA);
MValidationLookup[] validationLookups = new MValidationLookup[rows.size()];
for (int i = 0; i < rows.size(); i++) {
Element element = (Element) rows.get(i);
String[] data = split(element);
MValidationLookup validationLookup = buildValidationLookup();
setAttributes(validationLookup, columns, data);
validationLookups[i] = validationLookup;
}
return validationLookups;
}
private void attachValidationLookupType(Metadata metadata, Element root) throws MetaParseException {
List containers = root.elements(CONTAINER_VALIDATIONLOOKUPTYPE);
for (int i = 0; i < containers.size(); i++) {
Element container = (Element) containers.get(i);
MValidationLookup parent = metadata.getValidationLookup(getNonNullAttribute(container, ATTRIBUTE_RESOURCE),
getNonNullAttribute(container, ATTRIBUTE_VALIDATIONLOOKUP));
MValidationLookupType[] validationLookupTypes = processValidationLookupType(container);
for (int j = 0; j < validationLookupTypes.length; j++) {
parent.addChild(MetadataType.VALIDATION_LOOKUP_TYPE, validationLookupTypes[j]);
}
}
}
private MValidationLookupType[] processValidationLookupType(Element container) {
String[] columns = getColumns(container);
List rows = container.elements(DATA);
MValidationLookupType[] validationLookupTypes = new MValidationLookupType[rows.size()];
for (int i = 0; i < rows.size(); i++) {
Element element = (Element) rows.get(i);
String[] data = split(element);
MValidationLookupType validationLookupType = buildValidationLookupType();
setAttributes(validationLookupType, columns, data);
validationLookupTypes[i] = validationLookupType;
}
return validationLookupTypes;
}
private void attachValidationExternal(Metadata metadata, Element root) {
List containers = root.elements(CONTAINER_VALIDATIONEXTERNAL);
for (int i = 0; i < containers.size(); i++) {
Element container = (Element) containers.get(i);
MResource parent = metadata.getResource(container.attributeValue(ATTRIBUTE_RESOURCE));
MValidationExternal[] validationExternals = processValidationExternal(container);
for (int j = 0; j < validationExternals.length; j++) {
parent.addChild(MetadataType.VALIDATION_EXTERNAL, validationExternals[j]);
}
}
}
private MValidationExternal[] processValidationExternal(Element container) {
String[] columns = getColumns(container);
List rows = container.elements(DATA);
MValidationExternal[] validationExternals = new MValidationExternal[rows.size()];
for (int i = 0; i < rows.size(); i++) {
Element element = (Element) rows.get(i);
String[] data = split(element);
MValidationExternal validationExternal = buildValidationExternal();
setAttributes(validationExternal, columns, data);
validationExternals[i] = validationExternal;
}
return validationExternals;
}
private void attachValidationExternalType(Metadata metadata, Element root) throws MetaParseException {
List containers = root.elements(CONTAINER_VALIDATIONEXTERNALTYPE);
for (int i = 0; i < containers.size(); i++) {
Element container = (Element) containers.get(i);
MValidationExternal parent = metadata.getValidationExternal(getNonNullAttribute(container,
ATTRIBUTE_RESOURCE), getNonNullAttribute(container, ATTRIBUTE_VALIDATIONEXTERNAL));
MValidationExternalType[] validationExternalTypes = processValidationExternalType(container);
for (int j = 0; j < validationExternalTypes.length; j++) {
parent.addChild(MetadataType.VALIDATION_EXTERNAL_TYPE, validationExternalTypes[j]);
}
}
}
private MValidationExternalType[] processValidationExternalType(Element container) {
String[] columns = getColumns(container);
List rows = container.elements(DATA);
MValidationExternalType[] validationExternalTypes = new MValidationExternalType[rows.size()];
for (int i = 0; i < rows.size(); i++) {
Element element = (Element) rows.get(i);
String[] data = split(element);
MValidationExternalType validationExternalType = buildValidationExternalType();
setAttributes(validationExternalType, columns, data);
validationExternalTypes[i] = validationExternalType;
}
return validationExternalTypes;
}
private void attachValidationExpression(Metadata metadata, Element root) throws MetaParseException {
List containers = root.elements(CONTAINER_VALIDATIONEXPRESSION);
for (int i = 0; i < containers.size(); i++) {
Element container = (Element) containers.get(i);
MResource parent = metadata.getResource(getNonNullAttribute(container, ATTRIBUTE_RESOURCE));
MValidationExpression[] expressions = processValidationExpression(container);
for (int j = 0; j < expressions.length; j++) {
parent.addChild(MetadataType.VALIDATION_EXPRESSION, expressions[j]);
}
}
}
private MValidationExpression[] processValidationExpression(Element container) {
String[] columns = getColumns(container);
List rows = container.elements(DATA);
MValidationExpression[] expressions = new MValidationExpression[rows.size()];
for (int i = 0; i < expressions.length; i++) {
Element element = (Element) rows.get(i);
String[] data = split(element);
MValidationExpression expression = buildValidationExpression();
setAttributes(expression, columns, data);
expressions[i] = expression;
}
return expressions;
}
}

View File

@ -0,0 +1,628 @@
/*
* cart: CRT's Awesome RETS Tool
*
* Author: David Terrell
* Copyright (c) 2003, The National Association of REALTORS
* Distributed under a BSD-style license. See LICENSE.TXT for details.
*/
package com.ossez.usreio.tests.common.metadata;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.HashMap;
import com.ossez.usreio.tests.common.metadata.types.MClass;
import com.ossez.usreio.tests.common.metadata.types.MEditMask;
import com.ossez.usreio.tests.common.metadata.types.MForeignKey;
import com.ossez.usreio.tests.common.metadata.types.MLookup;
import com.ossez.usreio.tests.common.metadata.types.MLookupType;
import com.ossez.usreio.tests.common.metadata.types.MObject;
import com.ossez.usreio.tests.common.metadata.types.MResource;
import com.ossez.usreio.tests.common.metadata.types.MSearchHelp;
import com.ossez.usreio.tests.common.metadata.types.MSystem;
import com.ossez.usreio.tests.common.metadata.types.MTable;
import com.ossez.usreio.tests.common.metadata.types.MUpdate;
import com.ossez.usreio.tests.common.metadata.types.MUpdateHelp;
import com.ossez.usreio.tests.common.metadata.types.MUpdateType;
import com.ossez.usreio.tests.common.metadata.types.MValidationExpression;
import com.ossez.usreio.tests.common.metadata.types.MValidationExternal;
import com.ossez.usreio.tests.common.metadata.types.MValidationExternalType;
import com.ossez.usreio.tests.common.metadata.types.MValidationLookup;
import com.ossez.usreio.tests.common.metadata.types.MValidationLookupType;
import org.dom4j.Attribute;
import org.dom4j.Document;
import org.dom4j.Element;
/** Parses apart a complete Standard-XML response, returns a Metadata object */
public class JDomStandardBuilder extends MetadataBuilder {
public static final String ELEMENT_SYSTEM = "System";
public static final String ELEMENT_RESOURCE = "Resource";
public static final String ELEMENT_FOREIGNKEY = "ForeignKey";
public static final String ELEMENT_CLASS = "Class";
public static final String ELEMENT_TABLE = "Field";
public static final String ELEMENT_UPDATE = "UpdateType";
public static final String ELEMENT_UPDATETYPE = "UpdateField";
public static final String ELEMENT_OBJECT = "Object";
public static final String ELEMENT_SEARCHHELP = "SearchHelp";
public static final String ELEMENT_EDITMASK = "EditMask";
public static final String ELEMENT_UPDATEHELP = "UpdateHelp";
public static final String ELEMENT_LOOKUP = "Lookup";
public static final String ELEMENT_LOOKUPTYPE = "LookupType";
public static final String ELEMENT_VALIDATIONLOOKUP = "ValidationLookup";
public static final String ELEMENT_VALIDATIONLOOKUPTYPE = "ValidationLookupType";
public static final String ELEMENT_VALIDATIONEXPRESSION = "ValidationExpression";
public static final String ELEMENT_VALIDATIONEXTERNAL = "ValidationExternalType";
public static final String ELEMENT_VALIDATIONEXTERNALTYPE = "ValidationExternal";
public static final String ATTRIBUTE_RESOURCEID = ELEMENT_RESOURCE;
public static final String ATTRIBUTE_CLASSNAME = ELEMENT_CLASS;
public static final String ATTRIBUTE_UPDATE = ELEMENT_UPDATE;
public static final String ATTRIBUTE_LOOKUP = ELEMENT_LOOKUP;
public static final String ATTRIBUTE_VALIDATIONLOOKUP = ELEMENT_VALIDATIONLOOKUP;
public static final String ATTRIBUTE_VALIDATIONEXTERNAL = ELEMENT_VALIDATIONEXTERNAL;
public static final Map sType2Element = new HashMap();
static {
sType2Element.put(MetadataType.SYSTEM, ELEMENT_SYSTEM);
sType2Element.put(MetadataType.RESOURCE, ELEMENT_RESOURCE);
sType2Element.put(MetadataType.FOREIGNKEYS, ELEMENT_FOREIGNKEY);
sType2Element.put(MetadataType.CLASS, ELEMENT_CLASS);
sType2Element.put(MetadataType.TABLE, ELEMENT_TABLE);
sType2Element.put(MetadataType.UPDATE, ELEMENT_UPDATE);
sType2Element.put(MetadataType.UPDATE_TYPE, ELEMENT_UPDATETYPE);
sType2Element.put(MetadataType.SEARCH_HELP, ELEMENT_SEARCHHELP);
sType2Element.put(MetadataType.EDITMASK, ELEMENT_EDITMASK);
sType2Element.put(MetadataType.UPDATE_HELP, ELEMENT_UPDATEHELP);
sType2Element.put(MetadataType.LOOKUP, ELEMENT_LOOKUP);
sType2Element.put(MetadataType.LOOKUP_TYPE, ELEMENT_LOOKUPTYPE);
sType2Element.put(MetadataType.VALIDATION_LOOKUP, ELEMENT_VALIDATIONLOOKUP);
sType2Element.put(MetadataType.VALIDATION_LOOKUP_TYPE, ELEMENT_VALIDATIONLOOKUPTYPE);
sType2Element.put(MetadataType.VALIDATION_EXTERNAL, ELEMENT_VALIDATIONEXTERNAL);
sType2Element.put(MetadataType.VALIDATION_EXTERNAL_TYPE, ELEMENT_VALIDATIONEXTERNALTYPE);
sType2Element.put(MetadataType.VALIDATION_EXPRESSION, ELEMENT_VALIDATIONEXPRESSION);
}
@Override
public Metadata doBuild(Object src) throws MetadataException {
return build((Document) src);
}
public Metadata build(Document src) throws MetadataException {
Element element = src.getRootElement();
expectElement(element, CONTAINER_ROOT);
element = getElement(element, CONTAINER_METADATA);
return build(element);
}
@Override
public MetaObject[] parse(Object src) throws MetadataException {
return parse((Document) src);
}
public MetaObject[] parse(Document src) throws MetadataException {
Element element = src.getRootElement();
expectElement(element, CONTAINER_ROOT);
Element container = getElement(element, CONTAINER_METADATA);
boolean recurse = checkForRecursion(container);
List list = container.elements();
if (list.size() == 0) {
return null;
}
return processContainer(null, (Element) list.get(0), recurse);
}
/**
* Function to determine if a request contains recursive data or not.
* This is done here instead of inside processContainer because, well,
* it's easier and more reliable (processContainer might not figure out
* that a request is recursive until the third or 4th child if there are
* no children for the first couple of elements.
*
* @param top The outside METADATA container.
* @return true if the request is recursive
*
*/
private boolean checkForRecursion(Element top) {
/*
* this seems like a really nasty loop. However, if there are a
* lot of recursive elements, we'll find out pretty quickly, and if
* we fall all the way to the end then there probably wasn't that
* much to look through.
*/
Iterator children = top.elements().iterator();
while (children.hasNext()) {
/* each of these is a container (METADATA-*) type */
Element element = (Element) children.next();
Iterator iterator = element.elements().iterator();
while (iterator.hasNext()) {
/* each of these is an item element */
Element child = (Element) iterator.next();
Iterator subtypes = child.elements().iterator();
while (subtypes.hasNext()) {
Element subtype = (Element) subtypes.next();
if (subtype.getName().startsWith(CONTAINER_PREFIX)) {
return true;
}
}
}
}
return false;
}
private MetaObject[] processContainer(MetaObject parent, Element container, boolean recursion) {
MetadataType type = (MetadataType) sContainer2Type.get(container.getName());
if (type == null) {
throw new RuntimeException("no matching type for container " + container.getName());
}
List elements = container.elements((String) sType2Element.get(type));
String path = getPath(container);
List output = null;
if (parent == null) {
output = new LinkedList();
}
for (int i = 0; i < elements.size(); i++) {
Element element = (Element) elements.get(i);
MetaObject obj = newType(type);
setAttributes(obj, element);
if (output != null) {
output.add(obj);
}
if (parent != null) {
parent.addChild(type, obj);
} else {
/**
* Weirdness abounds. There IS an ID attribute of System,
* and the SystemID is included in the Metadata container
* attributes, but the system id is not part of the metadata
* request path for a getMetadata request, so we ignore it.
*/
if (!type.equals(MetadataType.SYSTEM)) {
obj.setPath(path);
}
}
if (recursion) {
MetadataType[] childTypes = obj.getChildTypes();
for (int j = 0; j < childTypes.length; j++) {
MetadataType childType = childTypes[j];
Element childContainer = element.element(CONTAINER_PREFIX + childType.name());
if (childContainer == null) {
obj.addChild(childType, null);
} else {
processContainer(obj, childContainer, true);
}
}
}
}
if (output == null) {
return null;
}
return (MetaObject[]) output.toArray(new MetaObject[0]);
}
String getPath(Element container) {
String resource = container.attributeValue(ATTRIBUTE_RESOURCEID);
if (resource == null) {
return null;
}
String classname = container.attributeValue(ATTRIBUTE_CLASSNAME);
if (classname != null) {
String update = container.attributeValue(ATTRIBUTE_UPDATE);
if (update != null) {
return resource + ":" + classname + ":" + update;
}
return resource + ":" + classname;
}
String lookup = container.attributeValue(ATTRIBUTE_LOOKUP);
if (lookup != null) {
return resource + ":" + lookup;
}
String vallkp = container.attributeValue(ATTRIBUTE_VALIDATIONLOOKUP);
if (vallkp != null) {
return resource + ":" + vallkp;
}
String vale = container.attributeValue(ATTRIBUTE_VALIDATIONEXTERNAL);
if (vale != null) {
return resource + ":" + vale;
}
return resource;
}
public Metadata build(Element element) throws MetadataException {
expectElement(element, CONTAINER_METADATA);
element = getElement(element, CONTAINER_SYSTEM);
//maybe i get the attribute here
MSystem sys = processSystem(element);
return new Metadata(sys);
}
private Element getElement(Element parent, String type) throws MetadataException {
Element element = parent.element(type);
if (element == null) {
throw new MetadataException("Missing element " + type);
}
return element;
}
private void expectElement(Element element, String type) throws MetadataException {
if (!element.getName().equalsIgnoreCase(type)) {// changed to ignore case
throw new MetadataException("Expecting element " + type + ", got " + element.getName());
}
}
private void setAttributes(MetaObject obj, Element el) {
List children = el.elements();
for (int i = 0; i < children.size(); i++) {
Element child = (Element) children.get(i);
String name = child.getName();
if (!name.startsWith(CONTAINER_PREFIX)) {
String value = child.getTextTrim();
setAttribute(obj, name, value);
} else {
// LOG.info("skipping container element " + name);
}
}
}
//when atrributes from the xml element are needed
public void setAttributesFromXMLAttr(MetaObject obj, Element el) {
Iterator attrIter = el.getParent().attributes().iterator();
while(attrIter.hasNext()){
Attribute attr = (Attribute) attrIter.next();
String name = attr.getName();
String value= attr.getValue().trim();
setAttribute(obj, name, value);
}
}
/**
* If we're a recursive request, initialize all possible child types so
* we don't have to try to pull them later, dynamically
*/
private void init(MetaObject item) {
MetadataType[] childTypes = item.getChildTypes();
for (int i = 0; i < childTypes.length; i++) {
MetadataType type = childTypes[i];
item.addChild(type, null);
}
}
private MSystem processSystem(Element container) {
Element element = container.element(ELEMENT_SYSTEM);
if (element == null){
element = container.element(ELEMENT_SYSTEM.toUpperCase());
}
MSystem system = buildSystem();
init(system);
setAttributesFromXMLAttr(system, element);
setAttributes(system, element);
Element child;
child = element.element(CONTAINER_RESOURCE);
if (child != null) {
processResource(system, child);
}
child = element.element(CONTAINER_FOREIGNKEY);
if (child != null) {
processForeignKey(system, child);
}
return system;
}
private void processResource(MSystem system, Element container) {
List resources = container.elements(ELEMENT_RESOURCE);
for (int i = 0; i < resources.size(); i++) {
Element element = (Element) resources.get(i);
MResource resource = buildResource();
init(resource);
setAttributes(resource, element);
system.addChild(MetadataType.RESOURCE, resource);
Element child;
child = element.element(CONTAINER_CLASS);
if (child != null) {
processClass(resource, child);
}
child = element.element(CONTAINER_OBJECT);
if (child != null) {
processObject(resource, child);
}
child = element.element(CONTAINER_SEARCH_HELP);
if (child != null) {
processSearchHelp(resource, child);
}
child = element.element(CONTAINER_EDITMASK);
if (child != null) {
processEditMask(resource, child);
}
child = element.element(CONTAINER_LOOKUP);
if (child != null) {
processLookup(resource, child);
}
child = element.element(CONTAINER_UPDATEHELP);
if (child != null) {
processUpdateHelp(resource, child);
}
child = element.element(CONTAINER_VALIDATIONLOOKUP);
if (child != null) {
processValidationLookup(resource, child);
}
child = element.element(CONTAINER_VALIDATIONEXPRESSION);
if (child != null) {
processValidationExpression(resource, child);
}
child = element.element(CONTAINER_VALIDATIONEXTERNAL);
if (child != null) {
processValidationExternal(resource, child);
}
}
}
private void processEditMask(MResource parent, Element container) {
List elements = container.elements(ELEMENT_EDITMASK);
for (int i = 0; i < elements.size(); i++) {
Element element = (Element) elements.get(i);
MEditMask mask = buildEditMask();
setAttributes(mask, element);
parent.addChild(MetadataType.EDITMASK, mask);
}
}
private void processLookup(MResource parent, Element container) {
List elements15 = container.elements(ELEMENT_LOOKUP);
List elements17 = container.elements(ELEMENT_LOOKUPTYPE);
List elements;
//some Rets Servers have lookuptype and lookup elements interchanged
if (elements15.isEmpty()){
elements = elements17;
} else {
elements = elements15;
}
for (int i = 0; i < elements.size(); i++) {
Element element = (Element) elements.get(i);
MLookup lookup = buildLookup();
init(lookup);
setAttributes(lookup, element);
parent.addChild(MetadataType.LOOKUP, lookup);
Element child = element.element(CONTAINER_LOOKUPTYPE);
if (child != null) {
processLookupType(lookup, child);
}
}
}
private void processLookupType(MLookup parent, Element container) {
List elements15 = container.elements(ELEMENT_LOOKUPTYPE);// check spec
List elements17 = container.elements(ELEMENT_LOOKUP);
List elements;
//some Rets Servers have lookuptype and lookup elements interchanged
if (elements15.isEmpty()){
elements = elements17;
} else {
elements = elements15;
}
for (int i = 0; i < elements.size(); i++) {
Element element = (Element) elements.get(i);
MLookupType type = buildLookupType();
setAttributes(type, element);
parent.addChild(MetadataType.LOOKUP_TYPE, type);
}
}
private void processUpdateHelp(MResource parent, Element container) {
List elements = container.elements(ELEMENT_UPDATEHELP);
for (int i = 0; i < elements.size(); i++) {
Element element = (Element) elements.get(i);
MUpdateHelp help = buildUpdateHelp();
setAttributes(help, element);
parent.addChild(MetadataType.UPDATE_HELP, help);
}
}
private void processValidationLookup(MResource parent, Element container) {
List elements = container.elements(ELEMENT_VALIDATIONLOOKUP);
for (int i = 0; i < elements.size(); i++) {
Element element = (Element) elements.get(i);
MValidationLookup lookup = buildValidationLookup();
init(lookup);
setAttributes(lookup, element);
parent.addChild(MetadataType.VALIDATION_LOOKUP, lookup);
Element child = element.element(CONTAINER_VALIDATIONLOOKUPTYPE);
if (child != null) {
processValidationLookupType(lookup, child);
}
}
}
private void processValidationLookupType(MValidationLookup parent, Element container) {
List elements = container.elements(ELEMENT_VALIDATIONLOOKUPTYPE);
for (int i = 0; i < elements.size(); i++) {
Element element = (Element) elements.get(i);
MValidationLookupType lookupType = buildValidationLookupType();
setAttributes(lookupType, element);
parent.addChild(MetadataType.VALIDATION_LOOKUP_TYPE, lookupType);
}
}
private void processValidationExpression(MResource parent, Element container) {
List elements = container.elements(ELEMENT_VALIDATIONEXPRESSION);
for (int i = 0; i < elements.size(); i++) {
Element element = (Element) elements.get(i);
MValidationExpression expression = buildValidationExpression();
setAttributes(expression, element);
parent.addChild(MetadataType.VALIDATION_EXPRESSION, expression);
}
}
private void processValidationExternal(MResource parent, Element container) {
List elements = container.elements(ELEMENT_VALIDATIONEXTERNAL);
for (int i = 0; i < elements.size(); i++) {
Element element = (Element) elements.get(i);
MValidationExternal external = buildValidationExternal();
init(external);
setAttributes(external, element);
parent.addChild(MetadataType.VALIDATION_EXTERNAL, external);
Element child = element.element(CONTAINER_VALIDATIONEXTERNALTYPE);
if (child != null) {
processValidationExternalType(external, child);
}
}
}
private void processValidationExternalType(MValidationExternal parent, Element container) {
List elements = container.elements(ELEMENT_VALIDATIONEXTERNALTYPE);
for (int i = 0; i < elements.size(); i++) {
Element element = (Element) elements.get(i);
MValidationExternalType type = buildValidationExternalType();
setAttributes(type, element);
parent.addChild(MetadataType.VALIDATION_EXTERNAL_TYPE, type);
}
}
private void processSearchHelp(MResource parent, Element container) {
List searchhelps = container.elements(ELEMENT_SEARCHHELP);
for (int i = 0; i < searchhelps.size(); i++) {
Element element = (Element) searchhelps.get(i);
MSearchHelp searchhelp = buildSearchHelp();
setAttributes(searchhelp, element);
parent.addChild(MetadataType.SEARCH_HELP, searchhelp);
}
}
private void processObject(MResource parent, Element container) {
List objects = container.elements(ELEMENT_OBJECT);
for (int i = 0; i < objects.size(); i++) {
Element element = (Element) objects.get(i);
MObject obj = buildObject();
setAttributes(obj, element);
parent.addChild(MetadataType.OBJECT, obj);
}
}
private void processClass(MResource parent, Element container) {
List classes = container.elements(ELEMENT_CLASS);
for (int i = 0; i < classes.size(); i++) {
Element element = (Element) classes.get(i);
MClass clazz = buildClass();
init(clazz);
setAttributes(clazz, element);
parent.addChild(MetadataType.CLASS, clazz);
Element child;
child = element.element(CONTAINER_TABLE);
if (child != null) {
processTable(clazz, child);
}
child = element.element(CONTAINER_UPDATE);
if (child != null) {
processUpdate(clazz, child);
}
}
}
private void processTable(MClass parent, Element container) {
List tables = container.elements(ELEMENT_TABLE);
for (int i = 0; i < tables.size(); i++) {
Element element = (Element) tables.get(i);
MTable table = buildTable();
setAttributes(table, element);
parent.addChild(MetadataType.TABLE, table);
}
}
private void processUpdate(MClass parent, Element container) {
List updates = container.elements(ELEMENT_UPDATE);
for (int i = 0; i < updates.size(); i++) {
Element element = (Element) updates.get(i);
MUpdate update = buildUpdate();
init(update);
setAttributes(update, element);
parent.addChild(MetadataType.UPDATE, update);
Element child = element.element(CONTAINER_UPDATE_TYPE);
if (child != null) {
processUpdateType(update, child);
}
}
}
private void processUpdateType(MUpdate parent, Element container) {
List updateFields = container.elements(ELEMENT_UPDATETYPE);
for (int i = 0; i < updateFields.size(); i++) {
Element element = (Element) updateFields.get(i);
MUpdateType updateType = buildUpdateType();
parent.addChild(MetadataType.UPDATE_TYPE, updateType);
setAttributes(updateType, element);
}
}
private void processForeignKey(MSystem system, Element container) {
List fkeys = container.elements("ForeignKey");
for (int i = 0; i < fkeys.size(); i++) {
Element element = (Element) fkeys.get(i);
MForeignKey foreignKey = buildForeignKey();
setAttributes(foreignKey, element);
system.addChild(MetadataType.FOREIGNKEYS, foreignKey);
}
}
public static final String CONTAINER_PREFIX = "METADATA-";
public static final String CONTAINER_ROOT = "RETS";
public static final String CONTAINER_METADATA = "METADATA";
public static final String CONTAINER_SYSTEM = "METADATA-SYSTEM";
public static final String CONTAINER_RESOURCE = "METADATA-RESOURCE";
public static final String CONTAINER_FOREIGNKEY = "METADATA-FOREIGN_KEYS";
public static final String CONTAINER_CLASS = "METADATA-CLASS";
public static final String CONTAINER_TABLE = "METADATA-TABLE";
public static final String CONTAINER_UPDATE = "METADATA-UPDATE";
public static final String CONTAINER_UPDATE_TYPE = "METADATA-UPDATE_TYPE";
public static final String CONTAINER_OBJECT = "METADATA-OBJECT";
public static final String CONTAINER_SEARCH_HELP = "METADATA-SEARCH_HELP";
public static final String CONTAINER_EDITMASK = "METADATA-EDITMASK";
public static final String CONTAINER_UPDATEHELP = "METADATA-UPDATE_HELP";
public static final String CONTAINER_LOOKUP = "METADATA-LOOKUP";
public static final String CONTAINER_LOOKUPTYPE = "METADATA-LOOKUP_TYPE";
public static final String CONTAINER_VALIDATIONLOOKUP = "METADATA-VALIDATION_LOOKUP";
public static final String CONTAINER_VALIDATIONLOOKUPTYPE = "METADATA-VALIDATION_LOOKUP_TYPE";
public static final String CONTAINER_VALIDATIONEXPRESSION = "METADATA-VALIDATION_EXPRESSION";
public static final String CONTAINER_VALIDATIONEXTERNAL = "METADATA-VALIDATION_EXTERNAL";
public static final String CONTAINER_VALIDATIONEXTERNALTYPE = "METADATA-VALIDATION_EXTERNAL_TYPE";
public static final Map sContainer2Type = new HashMap();
static {
for (int i = 0; i < MetadataType.values().length; i++) {
MetadataType type = MetadataType.values()[i];
sContainer2Type.put(CONTAINER_PREFIX + type.name(), type);
}
/* you have got to be kidding me. The spec (compact) says
METADATA-FOREIGNKEYS and that's the request type but the DTD says
METADATA-FOREIGN_KEY.
I think I'm going to be sick.
*/
sContainer2Type.remove(CONTAINER_PREFIX + MetadataType.FOREIGNKEYS.name());
sContainer2Type.put(CONTAINER_FOREIGNKEY, MetadataType.FOREIGNKEYS);
}
}

View File

@ -0,0 +1,20 @@
/*
* cart: CRT's Awesome RETS Tool
*
* Author: David Terrell
* Copyright (c) 2003, The National Association of REALTORS
* Distributed under a BSD-style license. See LICENSE.TXT for details.
*/
package com.ossez.usreio.tests.common.metadata;
import java.io.Serializable;
/** Interface for Metadata objects to collect their children. */
public interface MetaCollector extends Serializable {
/**
* @param path path to the parent object.
*/
public MetaObject[] getMetadata(MetadataType type, String path) throws MetadataException;
public MetaObject[] getMetadataRecursive(MetadataType type, String path) throws MetadataException;
}

View File

@ -0,0 +1,366 @@
package com.ossez.usreio.tests.common.metadata;
import java.io.Serializable;
import java.util.Collection;
import java.util.Collections;
//import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import com.ossez.usreio.common.util.CaseInsensitiveTreeMap;
import org.apache.commons.lang3.builder.EqualsBuilder;
import org.apache.commons.lang3.builder.HashCodeBuilder;
import org.apache.commons.lang3.builder.ToStringBuilder;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import com.ossez.usreio.tests.common.metadata.attrib.AttrAlphanum;
import com.ossez.usreio.tests.common.metadata.attrib.AttrBoolean;
import com.ossez.usreio.tests.common.metadata.attrib.AttrDate;
import com.ossez.usreio.tests.common.metadata.attrib.AttrNumeric;
import com.ossez.usreio.tests.common.metadata.attrib.AttrNumericPositive;
import com.ossez.usreio.tests.common.metadata.attrib.AttrPlaintext;
import com.ossez.usreio.tests.common.metadata.attrib.AttrText;
import com.ossez.usreio.tests.common.metadata.attrib.AttrVersion;
public abstract class MetaObject implements Serializable {
private static final Log LOG = LogFactory.getLog(MetaObject.class);
/** a standard parser used by different child types */
protected static final AttrType sAlphanum = new AttrAlphanum(0, 0);
protected static final AttrType sAlphanum64 = new AttrAlphanum(1, 64);
protected static final AttrType sAlphanum32 = new AttrAlphanum(1, 32);
protected static final AttrType sAlphanum24 = new AttrAlphanum(1, 24);
protected static final AttrType sAlphanum10 = new AttrAlphanum(1, 10);
protected static final AttrType sPlaintext = new AttrPlaintext(0, 0);
protected static final AttrType sPlaintext1024 = new AttrPlaintext(1, 1024);
protected static final AttrType sPlaintext512 = new AttrPlaintext(1, 512);
protected static final AttrType sPlaintext128 = new AttrPlaintext(1, 128);
protected static final AttrType sPlaintext64 = new AttrPlaintext(1, 64);
protected static final AttrType sPlaintext32 = new AttrPlaintext(1, 32);
protected static final AttrType sText = new AttrText(0, 0);
protected static final AttrType sText1024 = new AttrText(1, 1024);
protected static final AttrType sText512 = new AttrText(1, 512);
protected static final AttrType sText256 = new AttrText(1, 256);
protected static final AttrType sText128 = new AttrText(1, 128);
protected static final AttrType sText64 = new AttrText(1, 64);
protected static final AttrType sText32 = new AttrText(1, 32);
protected static final AttrType sAttrBoolean = new AttrBoolean();
protected static final AttrType sAttrDate = new AttrDate();
protected static final AttrType sAttrNumeric = new AttrNumeric();
protected static final AttrType sAttrNumericPositive = new AttrNumericPositive();
protected static final AttrType sAttrVersion = new AttrVersion();
protected static final AttrType sAttrMetadataEntryId = sAlphanum32;
protected static final MetadataType[] sNoChildren = new MetadataType[0];
protected static final AttrType retsid = sAlphanum32;
protected static final AttrType retsname = sAlphanum64;
public static final boolean STRICT_PARSING = true;
public static final boolean LOOSE_PARSING = false;
public static final boolean DEFAULT_PARSING = LOOSE_PARSING;
/** the metdata path to this object */
protected String path;
/** map of child type to map of child id to child object */
protected Map childTypes;
/** map of attribute name to attribute object (as parsed by attrtype) */
protected Map attributes;
/** map of attribute name to AttrType parser */
protected Map attrTypes;
private static Map<CacheKey,Map> sAttributeMapCache = new HashMap<CacheKey,Map>();
private MetaCollector mCollector;
private boolean strict;
public MetaObject(boolean strictParsing) {
this.strict = strictParsing;
if (strictParsing) {
this.attributes = new HashMap();
} else {
this.attributes = new CaseInsensitiveTreeMap();
}
this.attrTypes = this.getAttributeMap(strictParsing);
MetadataType[] types = getChildTypes();
this.childTypes = new HashMap();
for (int i = 0; i < types.length; i++) {
this.childTypes.put(types[i], null);
}
}
private Map getAttributeMap(boolean strictParsing) {
synchronized (sAttributeMapCache) {
Map<CacheKey,Map> map = sAttributeMapCache.get(new CacheKey(this, strictParsing));
if (map == null) {
if (strictParsing) {
map = new HashMap();
} else {
map = new CaseInsensitiveTreeMap();
}
addAttributesToMap(map);
// Let's make sure no one mucks with the map later
map = Collections.unmodifiableMap(map);
sAttributeMapCache.put(new CacheKey(this, strictParsing), map);
if (LOG.isDebugEnabled()) {
LOG.debug("Adding to attribute cache: " + this.getClass().getName() + ", " + strictParsing);
}
}
return map;
}
}
public static void clearAttributeMapCache() {
synchronized (sAttributeMapCache) {
sAttributeMapCache.clear();
}
}
public Collection getChildren(MetadataType type) {
if (!this.childTypes.containsKey(type)) {
// throw new IllegalArgumentException?
return null;
}
Object o = this.childTypes.get(type);
if (o == null) {
if (!fetchChildren(type)) {
return Collections.EMPTY_SET;
}
o = this.childTypes.get(type);
}
if (o instanceof Map) {
Map m = (Map) o;
return m.values();
}
return (Collection) o;
}
private boolean fetchChildren(MetadataType type) {
this.childTypes.put(type, new HashMap());
try {
MetaObject[] children = null;
if (this.mCollector != null) {
children = this.mCollector.getMetadata(type, getPath());
}
if (children == null) {
return false;
}
for (int i = 0; i < children.length; i++) {
MetaObject child = children[i];
addChild(type, child);
}
} catch (MetadataException e) {
LOG.error(toString() + " unable to fetch " + type.name() + " children");
return false;
}
return true;
}
public MetaObject getChild(MetadataType type, String id) {
if (id == null) {
return null;
}
try {
if (this.childTypes.get(type) == null && this.mCollector != null) {
if (!fetchChildren(type)) {
return null;
}
}
Map m = (Map) this.childTypes.get(type);
if (m == null) {
return null;
}
return (MetaObject) m.get(id);
} catch (ClassCastException e) {
return null;
}
}
public Object getAttribute(String key) {
return this.attributes.get(key);
}
public Set getKnownAttributes() {
return this.attrTypes.keySet();
}
public String getAttributeAsString(String key) {
Object value = this.attributes.get(key);
if (value == null) {
return null;
}
if (this.attrTypes.containsKey(key)) {
AttrType type = (AttrType) this.attrTypes.get(key);
return type.render(value);
}
return value.toString();
}
protected Object getTypedAttribute(String key, Class type) {
AttrType atype = (AttrType) this.attrTypes.get(key);
if (atype == null) {
return null;
}
if (atype.getType() == type) {
return this.attributes.get(key);
}
LOG.warn("type mismatch, expected " + type.getName() + " but" + " got " + atype.getType().getName());
return null;
}
public String getDateAttribute(String key) {
return (String) getTypedAttribute(key, String.class);
}
public String getStringAttribute(String key) {
return (String) getTypedAttribute(key, String.class);
}
public int getIntAttribute(String key) {
Integer i = (Integer) getTypedAttribute(key, Integer.class);
if (i == null) {
return 0;
}
return i.intValue();
}
public boolean getBooleanAttribute(String key) {
Boolean b = (Boolean) getTypedAttribute(key, Boolean.class);
if (b == null) {
return false;
}
return b.booleanValue();
}
public void setAttribute(String key, String value) {
if (value == null) {
// LOG.warning()
return;
}
if (this.attrTypes.containsKey(key)) {
AttrType type = (AttrType) this.attrTypes.get(key);
try {
this.attributes.put(key, type.parse(value,this.strict));
} catch (MetaParseException e) {
LOG.warn(toString() + " couldn't parse attribute " + key + ", value " + value + ": " + e.getMessage());
}
} else {
this.attributes.put(key, value);
LOG.warn("Unknown key (" + toString() + "): " + key);
}
}
public void addChild(MetadataType type, MetaObject child) {
if (this.childTypes.containsKey(type)) {
Object obj = this.childTypes.get(type);
Map map;
if (obj == null) {
map = new HashMap();
this.childTypes.put(type, map);
} else {
map = (Map) obj;
}
if (child == null) {
return;
}
String id = child.getId();
child.setPath(this.getPath());
child.setCollector(this.mCollector);
if (id != null) {
map.put(id, child);
}
return;
}
}
public String getId() {
String idAttr = getIdAttr();
if (idAttr == null) {
/** cheap hack so everything's a damn map */
return Integer.toString(hashCode());
}
return getAttributeAsString(idAttr);
}
public String getPath() {
return this.path;
}
protected void setPath(String parent) {
if (parent == null || parent.equals("")) {
this.path = getId();
} else {
this.path = parent + ":" + getId();
}
}
@Override
public String toString() {
ToStringBuilder tsb = new ToStringBuilder(this);
Iterator iter = getKnownAttributes().iterator();
while (iter.hasNext()) {
String key = (String) iter.next();
tsb.append(key, getAttributeAsString(key));
}
return tsb.toString();
}
public void setCollector(MetaCollector c) {
this.mCollector = c;
Iterator iterator = this.childTypes.keySet().iterator();
while (iterator.hasNext()) {
MetadataType type = (MetadataType) iterator.next();
Map map = (Map) this.childTypes.get(type);
if (map == null) {
continue;
}
Collection children = map.values();
for (Iterator iter = children.iterator(); iter.hasNext();) {
MetaObject object = (MetaObject) iter.next();
object.setCollector(c);
}
}
}
public abstract MetadataType[] getChildTypes();
protected abstract String getIdAttr();
/**
* Adds attributes to an attribute map. This is called by the MetaObject
* constructor to initialize a map of atributes. This map may be cached,
* so this method may not be called for every object construction.
*
* @param attributeMap Map to add attributes to
*/
protected abstract void addAttributesToMap(Map attributeMap);
}
class CacheKey {
private Class mClass;
private boolean strictParsing;
public CacheKey(MetaObject metaObject, boolean strictParsing) {
this.mClass = metaObject.getClass();
this.strictParsing = strictParsing;
}
@Override
public boolean equals(Object obj) {
if (!(obj instanceof CacheKey)) {
return false;
}
CacheKey rhs = (CacheKey) obj;
return new EqualsBuilder().append(this.mClass, rhs.mClass).append(this.strictParsing, rhs.strictParsing).isEquals();
}
@Override
public int hashCode() {
return new HashCodeBuilder().append(this.mClass).append(this.strictParsing).toHashCode();
}
}

View File

@ -0,0 +1,26 @@
/*
* cart: CRT's Awesome RETS Tool
*
* Author: David Terrell
* Copyright (c) 2003, The National Association of REALTORS
* Distributed under a BSD-style license. See LICENSE.TXT for details.
*/
package com.ossez.usreio.tests.common.metadata;
public class MetaParseException extends MetadataException {
public MetaParseException() {
super();
}
public MetaParseException(String msg) {
super(msg);
}
public MetaParseException(Throwable cause) {
super(cause);
}
public MetaParseException(String msg, Throwable cause) {
super(msg, cause);
}
}

View File

@ -0,0 +1,154 @@
package com.ossez.usreio.tests.common.metadata;
import java.io.Serializable;
import com.ossez.usreio.tests.common.metadata.types.MSystem;
import com.ossez.usreio.tests.common.metadata.types.MResource;
import com.ossez.usreio.tests.common.metadata.types.MForeignKey;
import com.ossez.usreio.tests.common.metadata.types.MClass;
import com.ossez.usreio.tests.common.metadata.types.MTable;
import com.ossez.usreio.tests.common.metadata.types.MUpdate;
import com.ossez.usreio.tests.common.metadata.types.MUpdateType;
import com.ossez.usreio.tests.common.metadata.types.MObject;
import com.ossez.usreio.tests.common.metadata.types.MValidationExternal;
import com.ossez.usreio.tests.common.metadata.types.MValidationLookup;
import com.ossez.usreio.tests.common.metadata.types.MLookup;
import com.ossez.usreio.tests.common.metadata.types.MSearchHelp;
public class Metadata implements Serializable {
protected MSystem system;
public Metadata(MetaCollector collector) throws MetadataException {
MetaObject[] sys = collector.getMetadata(MetadataType.SYSTEM, null);
if (sys != null && sys.length == 1) {
try {
this.system = (MSystem) sys[0];
} catch (ClassCastException e) {
throw new MetadataException(e);
}
this.system.setCollector(collector);
}
}
public Metadata(MSystem system) {
this.system = system;
}
public MSystem getSystem() {
return this.system;
}
public MResource getResource(String resourceId) {
return this.system.getMResource(resourceId);
}
public MForeignKey getForeignKey(String foreignKeyId) {
return this.system.getMForeignKey(foreignKeyId);
}
public MClass getMClass(String resourceId, String className) {
MResource resource = getResource(resourceId);
if (resource == null) {
return null;
}
return resource.getMClass(className);
}
public MTable getTable(String resourceId, String className, String systemName) {
MClass clazz = getMClass(resourceId, className);
if (clazz == null) {
return null;
}
return clazz.getMTable(systemName);
}
public MUpdate getUpdate(String resourceId, String className, String updateName) {
MClass clazz = getMClass(resourceId, className);
if (clazz == null) {
return null;
}
return clazz.getMUpdate(updateName);
}
public MUpdateType getUpdateType(String resourceId, String className, String updateName, String systemName) {
MUpdate update = getUpdate(resourceId, className, updateName);
if (update == null) {
return null;
}
return update.getMUpdateType(systemName);
}
public MObject getObject(String resourceId, String objectType) {
MResource resource = getResource(resourceId);
if (resource == null) {
return null;
}
return resource.getMObject(objectType);
}
public MLookup getLookup(String resourceId, String lookupName) {
MResource resource = getResource(resourceId);
if (resource == null) {
return null;
}
return resource.getMLookup(lookupName);
}
public MSearchHelp getSearchHelp(String resourceId, String searchHelpId) {
MResource resource = getResource(resourceId);
if (resource == null) {
return null;
}
return resource.getMSearchHelp(searchHelpId);
}
public MValidationExternal getValidationExternal(String resourceId, String validationExternalName) {
MResource resource = getResource(resourceId);
if (resource == null) {
return null;
}
return resource.getMValidationExternal(validationExternalName);
}
public MValidationLookup getValidationLookup(String resourceId, String validationLookupName) {
MResource resource = getResource(resourceId);
if (resource == null) {
return null;
}
return resource.getMValidationLookup(validationLookupName);
}
private String getResourceId(MetaObject obj) {
String path = obj.getPath();
int index = path.indexOf(':');
if (index == -1) {
return null;
}
String resource = path.substring(0, index);
return resource;
}
public MResource getResource(MTable field) {
String resource = getResourceId(field);
return getResource(resource);
}
public MLookup getLookup(MTable field) {
String resource = getResourceId(field);
return getLookup(resource, field.getLookupName());
}
public MSearchHelp getSearchHelp(MTable field) {
String searchHelpID = field.getSearchHelpID();
if (searchHelpID == null) {
return null;
}
String resource = getResourceId(field);
return getSearchHelp(resource, searchHelpID);
}
public MResource getResource(MClass clazz) {
return getResource(getResourceId(clazz));
}
}

View File

@ -0,0 +1,203 @@
/*
* cart: CRT's Awesome RETS Tool
*
* Author: David Terrell
* Copyright (c) 2003, The National Association of REALTORS
* Distributed under a BSD-style license. See LICENSE.TXT for details.
*/
package com.ossez.usreio.tests.common.metadata;
import com.ossez.usreio.tests.common.metadata.types.MClass;
import com.ossez.usreio.tests.common.metadata.types.MEditMask;
import com.ossez.usreio.tests.common.metadata.types.MForeignKey;
import com.ossez.usreio.tests.common.metadata.types.MLookup;
import com.ossez.usreio.tests.common.metadata.types.MLookupType;
import com.ossez.usreio.tests.common.metadata.types.MObject;
import com.ossez.usreio.tests.common.metadata.types.MResource;
import com.ossez.usreio.tests.common.metadata.types.MSearchHelp;
import com.ossez.usreio.tests.common.metadata.types.MSystem;
import com.ossez.usreio.tests.common.metadata.types.MTable;
import com.ossez.usreio.tests.common.metadata.types.MUpdate;
import com.ossez.usreio.tests.common.metadata.types.MUpdateHelp;
import com.ossez.usreio.tests.common.metadata.types.MUpdateType;
import com.ossez.usreio.tests.common.metadata.types.MValidationExpression;
import com.ossez.usreio.tests.common.metadata.types.MValidationExternal;
import com.ossez.usreio.tests.common.metadata.types.MValidationExternalType;
import com.ossez.usreio.tests.common.metadata.types.MValidationLookup;
import com.ossez.usreio.tests.common.metadata.types.MValidationLookupType;
public abstract class MetadataBuilder {
protected MetadataBuilder() {
this.mStrict = false;
}
public boolean isStrict() {
return this.mStrict;
}
public void setStrict(boolean strict) {
this.mStrict = strict;
}
protected Metadata finish(MSystem system) {
return new Metadata(system);
}
protected static void setAttribute(MetaObject obj, String key, String value) {
obj.setAttribute(key, value);
}
protected MSystem buildSystem() {
MSystem system = new MSystem(this.mStrict);
return system;
}
protected MResource buildResource() {
MResource resource = new MResource(this.mStrict);
return resource;
}
protected MForeignKey buildForeignKey() {
MForeignKey key = new MForeignKey(this.mStrict);
return key;
}
protected MClass buildClass() {
MClass clazz = new MClass(this.mStrict);
return clazz;
}
protected MTable buildTable() {
MTable table = new MTable(this.mStrict);
return table;
}
protected MUpdate buildUpdate() {
MUpdate update = new MUpdate(this.mStrict);
return update;
}
protected MUpdateType buildUpdateType() {
MUpdateType updatetype = new MUpdateType(this.mStrict);
return updatetype;
}
protected MObject buildObject() {
MObject obj = new MObject(this.mStrict);
return obj;
}
protected MSearchHelp buildSearchHelp() {
MSearchHelp help = new MSearchHelp(this.mStrict);
return help;
}
protected MEditMask buildEditMask() {
MEditMask mask = new MEditMask(this.mStrict);
return mask;
}
protected MLookup buildLookup() {
MLookup lookup = new MLookup(this.mStrict);
return lookup;
}
protected MLookupType buildLookupType() {
MLookupType type = new MLookupType(this.mStrict);
return type;
}
protected MUpdateHelp buildUpdateHelp() {
MUpdateHelp help = new MUpdateHelp(this.mStrict);
return help;
}
protected MValidationLookup buildValidationLookup() {
MValidationLookup lookup = new MValidationLookup(this.mStrict);
return lookup;
}
protected MValidationExternalType buildValidationExternalType() {
MValidationExternalType type = new MValidationExternalType(this.mStrict);
return type;
}
protected MValidationExpression buildValidationExpression() {
MValidationExpression expression = new MValidationExpression(this.mStrict);
return expression;
}
protected MValidationExternal buildValidationExternal() {
MValidationExternal external = new MValidationExternal(this.mStrict);
return external;
}
protected MValidationLookupType buildValidationLookupType() {
MValidationLookupType lookupType = new MValidationLookupType(this.mStrict);
return lookupType;
}
public abstract Metadata doBuild(Object src) throws MetadataException;
public abstract MetaObject[] parse(Object src) throws MetadataException;
protected MetaObject newType(MetadataType type) {
if (type == MetadataType.SYSTEM) {
return buildSystem();
}
if (type == MetadataType.RESOURCE) {
return buildResource();
}
if (type == MetadataType.FOREIGNKEYS) {
return buildForeignKey();
}
if (type == MetadataType.CLASS) {
return buildClass();
}
if (type == MetadataType.TABLE) {
return buildTable();
}
if (type == MetadataType.UPDATE) {
return buildUpdate();
}
if (type == MetadataType.UPDATE_TYPE) {
return buildUpdateType();
}
if (type == MetadataType.OBJECT) {
return buildObject();
}
if (type == MetadataType.SEARCH_HELP) {
return buildSearchHelp();
}
if (type == MetadataType.EDITMASK) {
return buildEditMask();
}
if (type == MetadataType.UPDATE_HELP) {
return buildUpdateHelp();
}
if (type == MetadataType.LOOKUP) {
return buildLookup();
}
if (type == MetadataType.LOOKUP_TYPE) {
return buildLookupType();
}
if (type == MetadataType.VALIDATION_LOOKUP) {
return buildValidationLookup();
}
if (type == MetadataType.VALIDATION_LOOKUP_TYPE) {
return buildValidationLookupType();
}
if (type == MetadataType.VALIDATION_EXTERNAL) {
return buildValidationExternal();
}
if (type == MetadataType.VALIDATION_EXTERNAL_TYPE) {
return buildValidationExternalType();
}
if (type == MetadataType.VALIDATION_EXPRESSION) {
return buildValidationExpression();
}
throw new RuntimeException("No metadata type class found for " + type.name());
}
private boolean mStrict;
}

View File

@ -0,0 +1,31 @@
package com.ossez.usreio.tests.common.metadata;
public enum MetadataElement {
SYSTEM("System"),// might need to provide enumeration for different versions 1.5 vs 1.7
RESOURCE("Resource"),
FOREIGNKEY("ForeignKey"),
CLASS("Class"),
TABLE("Field"),
UPDATE("UpdateType"),
UPDATETYPE("UpdateField"),
OBJECT("Object"),
SEARCHHELP("SearchHelp"),
EDITMASK("EditMask"),
UPDATEHELP("UpdateHelp"),
LOOKUP("Lookup"),
LOOKUPTYPE("LookupType"),
VALIDATIONLOOKUP("ValidationLookup"),
VALIDATIONLOOKUPTYPE("ValidationLookupType"),
VALIDATIONEXPRESSION("ValidationExpression"),
VALIDATIONEXTERNAL("ValidationExternalType"),
VALIDATIONEXTERNALTYPE("ValidationExternal");
private final String elementName;
MetadataElement(String elementName){
this.elementName = elementName;
}
public String elementName(){ return this.elementName;}
}

View File

@ -0,0 +1,27 @@
/*
* cart: CRT's Awesome RETS Tool
*
* Author: David Terrell
* Copyright (c) 2003, The National Association of REALTORS
* Distributed under a BSD-style license. See LICENSE.TXT for details.
*/
package com.ossez.usreio.tests.common.metadata;
public class MetadataException extends Exception {
public MetadataException() {
super();
}
public MetadataException(String msg) {
super(msg);
}
public MetadataException(Throwable cause) {
super(cause);
}
public MetadataException(String msg, Throwable cause) {
super(msg, cause);
}
}

View File

@ -0,0 +1,30 @@
/*
* cart: CRT's Awesome RETS Tool
*
* Author: David Terrell
* Copyright (c) 2003, The National Association of REALTORS
* Distributed under a BSD-style license. See LICENSE.TXT for details.
*/
package com.ossez.usreio.tests.common.metadata;
public enum MetadataType {
EDITMASK,
FOREIGNKEYS,
RESOURCE,
LOOKUP,
LOOKUP_TYPE,
OBJECT,
SEARCH_HELP,
SYSTEM,
TABLE,
UPDATE,
UPDATE_HELP,
UPDATE_TYPE,
VALIDATION_EXPRESSION,
VALIDATION_EXTERNAL,
VALIDATION_EXTERNAL_TYPE,
VALIDATION_LOOKUP,
VALIDATION_LOOKUP_TYPE,
CLASS;
}

View File

@ -0,0 +1,49 @@
/*
* cart: CRT's Awesome RETS Tool
*
* Author: David Terrell
* Copyright (c) 2003, The National Association of REALTORS
* Distributed under a BSD-style license. See LICENSE.TXT for details.
*/
package com.ossez.usreio.tests.common.metadata.attrib;
import com.ossez.usreio.tests.common.metadata.AttrType;
import com.ossez.usreio.tests.common.metadata.MetaParseException;
public abstract class AttrAbstractText implements AttrType<String> {
protected int min;
protected int max;
public AttrAbstractText(int min, int max) {
this.min = min;
this.max = max;
}
public String parse(String value, boolean strict) throws MetaParseException {
if( !strict )
return value;
int l = value.length();
if (this.min != 0 && l < this.min) {
throw new MetaParseException("Value too short (min " + this.min + "): " + l);
}
if (this.max != 0 && l > this.max) {
throw new MetaParseException("Value too long (max " + this.max + "): " + l);
}
checkContent(value);
return value;
}
public Class<String> getType() {
return String.class;
}
public String render(String value) {
return value;
}
protected abstract void checkContent(String value) throws MetaParseException;
}

View File

@ -0,0 +1,31 @@
/*
* cart: CRT's Awesome RETS Tool
*
* Author: David Terrell
* Copyright (c) 2003, The National Association of REALTORS
* Distributed under a BSD-style license. See LICENSE.TXT for details.
*/
package com.ossez.usreio.tests.common.metadata.attrib;
import com.ossez.usreio.tests.common.metadata.MetaParseException;
public class AttrAlphanum extends AttrAbstractText {
public AttrAlphanum(int min, int max) {
super(min, max);
}
@Override
protected void checkContent(String value) throws MetaParseException {
char[] chars = value.toCharArray();
for (int i = 0; i < chars.length; i++) {
char c = chars[i];
if (!Character.isLetterOrDigit(c)) {
// illegal but exist in CRT metadata
if ("_- ".indexOf(c) == -1) {
throw new MetaParseException("Invalid Alphanum character at position " + i + ": " + c);
}
}
}
}
}

View File

@ -0,0 +1,54 @@
/*
* cart: CRT's Awesome RETS Tool
*
* Author: David Terrell
* Copyright (c) 2003, The National Association of REALTORS
* Distributed under a BSD-style license. See LICENSE.TXT for details.
*/
package com.ossez.usreio.tests.common.metadata.attrib;
import com.ossez.usreio.tests.common.metadata.AttrType;
import com.ossez.usreio.tests.common.metadata.MetaParseException;
public class AttrBoolean implements AttrType<Boolean> {
public Boolean parse(String value, boolean strict) throws MetaParseException {
if (value.equals("1")) {
return Boolean.TRUE;
}
if (value.equals("0")) {
return Boolean.FALSE;
}
if (value.equalsIgnoreCase("true")) {
return Boolean.TRUE;
}
if (value.equalsIgnoreCase("false")) {
return Boolean.FALSE;
}
if (value.equalsIgnoreCase("Y")) {
return Boolean.TRUE;
}
if (value.equalsIgnoreCase("N")) {
return Boolean.FALSE;
}
if (value.equals("")) {
return Boolean.FALSE;
}
if( strict )
throw new MetaParseException("Invalid boolean value: " + value);
return false;
}
public String render(Boolean value) {
if( value.booleanValue() ) return "1";
return "0";
}
public Class<Boolean> getType() {
return Boolean.class;
}
}

View File

@ -0,0 +1,71 @@
/*
* cart: CRT's Awesome RETS Tool
*
* Author: David Terrell
* Copyright (c) 2003, The National Association of REALTORS
* Distributed under a BSD-style license. See LICENSE.TXT for details.
*
*
* Vangulo Changed:
* gives ability to handle dates in this format
* 2011-06-01T18:06:58
* should find a more elegant way
*/
package com.ossez.usreio.tests.common.metadata.attrib;
//import java.text.DateFormat;
//import java.text.ParseException;
//import java.text.SimpleDateFormat;
//import java.util.Date;
import com.ossez.usreio.tests.common.metadata.AttrType;
import com.ossez.usreio.tests.common.metadata.MetaParseException;
/**
* Converted this class to return a String instead of a
* Date object which allows for more flexiblity since
* Many Rets Servers format their dates differently
*
* @author vangulo
*
*/
public class AttrDate implements AttrType<String> {
// need date attribute to be flexible since different MLS's have
// different formats for dates
public String parse(String value, boolean strict) throws MetaParseException {
return value;
// Date d;
// try {
// d = this.df.parse(value);
// } catch (ParseException e) {
// if( strict )
// throw new MetaParseException(e);
// try {
// value = value.replaceAll("[A-Za-z]", " ");
// d = this.df1.parse(value);
// } catch (ParseException e1) {
// //e1.printStackTrace();
// return value;
// }
// return d;
// }
// return d;
}
public String render(String value) {
return value;
//Date date = value;
//return this.df.format(date);
}
public Class<String> getType() {
return String.class;
}
//private DateFormat df = new SimpleDateFormat("E, d MMM yyyy HH:mm:ss z");
//2011-06-01T18:06:58
//private DateFormat df1 = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
//Tuesday, 22-Dec-2009 21:03:18 GMT
//private DateFormat df2 = new SimpleDateFormat("E, dd-MMM-yyyy HH:mm:ss z");
}

View File

@ -0,0 +1,31 @@
/*
* cart: CRT's Awesome RETS Tool
*
* Author: David Terrell
* Copyright (c) 2003, The National Association of REALTORS
* Distributed under a BSD-style license. See LICENSE.TXT for details.
*/
package com.ossez.usreio.tests.common.metadata.attrib;
import java.util.HashMap;
import java.util.Map;
import java.util.Collections;
import com.ossez.usreio.tests.common.metadata.MetaParseException;
public class AttrEnum extends AttrAbstractText {
public AttrEnum(String[] values) {
super(0, 0);
this.map = new HashMap<String,String>();
for (String value : values) this.map.put(value, value);
this.map = Collections.unmodifiableMap(this.map);
}
@Override
protected void checkContent(String value) throws MetaParseException {
if( !this.map.containsKey(value) )
throw new MetaParseException("Invalid key: " + value);
}
private Map<String,String> map;
}

View File

@ -0,0 +1,31 @@
/*
* cart: CRT's Awesome RETS Tool
*
* Author: David Terrell
* Copyright (c) 2003, The National Association of REALTORS
* Distributed under a BSD-style license. See LICENSE.TXT for details.
*/
package com.ossez.usreio.tests.common.metadata.attrib;
import com.ossez.usreio.tests.common.metadata.MetaParseException;
public class AttrGenericText extends AttrAbstractText {
private String mChars;
public AttrGenericText(int min, int max, String chars) {
super(min, max);
this.mChars = chars;
}
@Override
protected void checkContent(String value) throws MetaParseException {
char[] chars = value.toCharArray();
for (int i = 0; i < chars.length; i++) {
char c = chars[i];
if (this.mChars.indexOf(c) == -1) {
throw new MetaParseException("Invalid char (" + c + ") at position " + i);
}
}
}
}

View File

@ -0,0 +1,31 @@
/*
* cart: CRT's Awesome RETS Tool
*
* Author: David Terrell
* Copyright (c) 2003, The National Association of REALTORS
* Distributed under a BSD-style license. See LICENSE.TXT for details.
*/
package com.ossez.usreio.tests.common.metadata.attrib;
import com.ossez.usreio.tests.common.metadata.AttrType;
import com.ossez.usreio.tests.common.metadata.MetaParseException;
public class AttrNumeric implements AttrType<Integer> {
public Integer parse(String value, boolean strict) throws MetaParseException {
try {
return new Integer(value);
} catch (NumberFormatException e) {
if( strict )
throw new MetaParseException(e);
return 0;
}
}
public String render(Integer value) {
return value.toString();
}
public Class<Integer> getType() {
return Integer.class;
}
}

View File

@ -0,0 +1,36 @@
/*
* cart: CRT's Awesome RETS Tool
*
* Author: David Terrell
* Copyright (c) 2003, The National Association of REALTORS
* Distributed under a BSD-style license. See LICENSE.TXT for details.
*/
package com.ossez.usreio.tests.common.metadata.attrib;
import com.ossez.usreio.tests.common.metadata.AttrType;
import com.ossez.usreio.tests.common.metadata.MetaParseException;
public class AttrNumericPositive implements AttrType<Integer> {
public Integer parse(String value, boolean strict) throws MetaParseException {
try {
Integer integer = new Integer(value);
if (strict && integer < 1) throw new IllegalArgumentException(String.format("%s is not positive", value));
return integer;
} catch (Exception e) {
if( strict )
throw new MetaParseException(e);
return 1;
}
}
public String render(Integer value) {
return value.toString();
}
public Class<Integer> getType() {
return Integer.class;
}
}

View File

@ -0,0 +1,28 @@
/*
* cart: CRT's Awesome RETS Tool
*
* Author: David Terrell
* Copyright (c) 2003, The National Association of REALTORS
* Distributed under a BSD-style license. See LICENSE.TXT for details.
*/
package com.ossez.usreio.tests.common.metadata.attrib;
import com.ossez.usreio.tests.common.metadata.MetaParseException;
public class AttrPlaintext extends AttrAbstractText {
public AttrPlaintext(int min, int max) {
super(min, max);
}
@Override
protected void checkContent(String value) throws MetaParseException {
char[] chars = value.toCharArray();
for (int i = 0; i < chars.length; i++) {
char c = chars[i];
if (c < 31 || c > 126) {
throw new MetaParseException("Invalid character (ordinal " + (int) c + ") at position " + i);
}
}
}
}

View File

@ -0,0 +1,28 @@
/*
* cart: CRT's Awesome RETS Tool
*
* Author: David Terrell
* Copyright (c) 2003, The National Association of REALTORS
* Distributed under a BSD-style license. See LICENSE.TXT for details.
*/
package com.ossez.usreio.tests.common.metadata.attrib;
import com.ossez.usreio.tests.common.metadata.MetaParseException;
public class AttrText extends AttrAbstractText {
public AttrText(int min, int max) {
super(min, max);
}
@Override
protected void checkContent(String value) throws MetaParseException {
char[] chars = value.toCharArray();
for (int i = 0; i < chars.length; i++) {
char c = chars[i];
if (!(c == '\n' || c == '\r' || c == ' ' || c == '\t' || (c > 31 && c < 127))) {
throw new MetaParseException("Invalid character (ordinal " + (int) c + ") at position " + i);
}
}
}
}

View File

@ -0,0 +1,66 @@
/*
* cart: CRT's Awesome RETS Tool
*
* Author: David Terrell
* Copyright (c) 2003, The National Association of REALTORS
* Distributed under a BSD-style license. See LICENSE.TXT for details.
*/
package com.ossez.usreio.tests.common.metadata.attrib;
import org.apache.commons.lang3.StringUtils;
import com.ossez.usreio.tests.common.metadata.AttrType;
import com.ossez.usreio.tests.common.metadata.MetaParseException;
/**
* A version is a string formatted "major.minor.release". This gets converted
* to an integer such as major * 10,000,000 + minor * 100,000 + release.
*/
public class AttrVersion implements AttrType<Integer> {
public Integer parse(String value, boolean strict) throws MetaParseException {
String[] parts = StringUtils.split(value, ".");
int major, minor, release;
if (strict && parts != null && parts.length != 3) {
throw new MetaParseException("Invalid version: " + value + ", " + parts.length + " parts");
}
try {
major = Integer.parseInt(this.getPart(parts,0));
minor = Integer.parseInt(this.getPart(parts,1));
release = Integer.parseInt(this.getPart(parts,2));
} catch (NumberFormatException e) {
throw new MetaParseException("Invalid version: " + value, e);
}
if ((major < 100) && (major >= 0) && (minor < 100) && (minor >= 0) && (release < 100000) && (release >= 0)) {
return new Integer(major * 10000000 + minor * 100000 + release);
}
if( strict )
throw new MetaParseException("Invalid version: " + value);
return 0;
}
private String getPart(String[] parts, int part){
if( parts != null && parts.length > part ) return parts[part];
return "0";
}
public String render(Integer value) {
int ver = value.intValue();
int release = ver % 100000;
int minor = (ver / 100000) % 100;
int major = (ver / 10000000);
String minstr = Integer.toString(minor);
String relstr = Integer.toString(release);
while (minstr.length() < 2) {
minstr = "0" + minstr;
}
while (relstr.length() < 5) {
relstr = "0" + relstr;
}
return major + "." + minstr + "." + relstr;
}
public Class<Integer> getType() {
return Integer.class;
}
}

View File

@ -0,0 +1,126 @@
package com.ossez.usreio.tests.common.metadata.types;
import java.util.Collection;
//import java.util.Date;
import java.util.Map;
import com.ossez.usreio.tests.common.metadata.MetaObject;
import com.ossez.usreio.tests.common.metadata.MetadataType;
public class MClass extends MetaObject {
public static final String CLASSNAME = "ClassName";
public static final String VISIBLENAME = "VisibleName";
public static final String STANDARDNAME = "StandardName";
public static final String DESCRIPTION = "Description";
public static final String TABLEVERSION = "TableVersion";
public static final String TABLEDATE = "TableDate";
public static final String UPDATEVERSION = "UpdateVersion";
public static final String UPDATEDATE = "UpdateDate";
public static final String DELETEDFLAGFIELD = "DeletedFlagField";
public static final String DELETEDFLAGVALUE = "DeletedFlagValue";
public static final String CLASSTIMESTAMP = "ClassTimeStamp";
public static final String HASHKEYINDEX = "HasKeyIndex";
private static MetadataType[] sTypes = { MetadataType.UPDATE, MetadataType.TABLE };
public MClass() {
this(DEFAULT_PARSING);
}
public MClass(boolean strictParsing) {
super(strictParsing);
}
@Override
public MetadataType[] getChildTypes() {
return sTypes;
}
public String getClassName() {
return getStringAttribute(CLASSNAME);
}
public String getVisibleName() {
return getStringAttribute(VISIBLENAME);
}
public String getStandardName() {
return getStringAttribute(STANDARDNAME);
}
public String getDescription() {
return getStringAttribute(DESCRIPTION);
}
public int getTableVersion() {
return getIntAttribute(TABLEVERSION);
}
public String getTableDate() {
return getDateAttribute(TABLEDATE);
}
public int getUpdateVersion() {
return getIntAttribute(UPDATEVERSION);
}
public String getUpdateDate() {
return getDateAttribute(UPDATEDATE);
}
public MUpdate getMUpdate(String updateName) {
return (MUpdate) getChild(MetadataType.UPDATE, updateName);
}
public MUpdate[] getMUpdates() {
MUpdate[] tmpl = new MUpdate[0];
return (MUpdate[]) getChildren(MetadataType.UPDATE).toArray(tmpl);
}
public MTable getMTable(String systemName) {
return (MTable) getChild(MetadataType.TABLE, systemName);
}
public MTable[] getMTables() {
Collection children = getChildren(MetadataType.TABLE);
return (MTable[]) children.toArray(new MTable[0]);
}
@Override
protected String getIdAttr() {
return CLASSNAME;
}
@Override
protected void addAttributesToMap(Map attributeMap) {
attributeMap.put(CLASSNAME, sAlphanum32);
attributeMap.put(VISIBLENAME, sPlaintext32);
attributeMap.put(STANDARDNAME, sAlphanum32);
attributeMap.put(DESCRIPTION, sPlaintext128);
attributeMap.put(TABLEVERSION, sAttrVersion);
attributeMap.put(TABLEDATE, sAttrDate);
attributeMap.put(UPDATEVERSION, sAttrVersion);
attributeMap.put(UPDATEDATE, sAttrDate);
attributeMap.put(DELETEDFLAGFIELD, retsname);
attributeMap.put(DELETEDFLAGVALUE, sAlphanum32);
attributeMap.put(CLASSTIMESTAMP, retsname);
attributeMap.put(HASHKEYINDEX, sAttrBoolean);
}
public String getDeletedFlagField() {
return getStringAttribute(DELETEDFLAGFIELD);
}
public String getDeletedFlagValue() {
return getStringAttribute(DELETEDFLAGVALUE);
}
public String getClassTimeStamp() {
return getStringAttribute(CLASSTIMESTAMP);
}
public String getHashKeyIndex() {
return getStringAttribute(HASHKEYINDEX);
}
}

View File

@ -0,0 +1,50 @@
package com.ossez.usreio.tests.common.metadata.types;
import java.util.Map;
import com.ossez.usreio.tests.common.metadata.MetaObject;
import com.ossez.usreio.tests.common.metadata.MetadataType;
public class MEditMask extends MetaObject {
public static final String METADATAENTRYID = "MetadataEntryID";
public static final String EDITMASKID = "EditMaskID";
public static final String VALUE = "Value";
public MEditMask() {
this(DEFAULT_PARSING);
}
public MEditMask(boolean strictParsing) {
super(strictParsing);
}
public String getMetadataEntryID() {
return getStringAttribute(METADATAENTRYID);
}
public String getEditMaskID() {
return getStringAttribute(EDITMASKID);
}
public String getValue() {
return getStringAttribute(VALUE);
}
@Override
public MetadataType[] getChildTypes() {
return sNoChildren;
}
@Override
protected String getIdAttr() {
return EDITMASKID;
}
@Override
protected void addAttributesToMap(Map attributeMap) {
attributeMap.put(METADATAENTRYID, sAttrMetadataEntryId);
attributeMap.put(EDITMASKID, sAlphanum32);
attributeMap.put(VALUE, sText256);
}
}

View File

@ -0,0 +1,87 @@
package com.ossez.usreio.tests.common.metadata.types;
import java.util.Map;
import com.ossez.usreio.tests.common.metadata.MetaObject;
import com.ossez.usreio.tests.common.metadata.MetadataType;
public class MForeignKey extends MetaObject {
public static final String FOREIGNKEYID = "ForeignKeyID";
public static final String PARENTRESOURCEID = "ParentResourceID";
public static final String PARENTCLASSID = "ParentClassID";
public static final String PARENTSYSTEMNAME = "ParentSystemName";
public static final String CHILDRESOURCEID = "ChildResourceID";
public static final String CHILDCLASSID = "ChildClassID";
public static final String CHILDSYSTEMNAME = "ChildSystemName";
public static final String CONDITIONALPARENTFIELD = "ConditionalParentField";
public static final String CONDITIONALPARENTVALUE = "ConditionalParentValue";
public MForeignKey() {
this(DEFAULT_PARSING);
}
public MForeignKey(boolean strictParsing) {
super(strictParsing);
}
public String getForeignKeyID() {
return getStringAttribute(FOREIGNKEYID);
}
public String getParentResourceID() {
return getStringAttribute(PARENTRESOURCEID);
}
public String getParentClassID() {
return getStringAttribute(PARENTCLASSID);
}
public String getParentSystemName() {
return getStringAttribute(PARENTSYSTEMNAME);
}
public String getChildResourceID() {
return getStringAttribute(CHILDRESOURCEID);
}
public String getChildClassID() {
return getStringAttribute(CHILDCLASSID);
}
public String getChildSystemName() {
return getStringAttribute(CHILDSYSTEMNAME);
}
public String getConditionalParentField() {
return getStringAttribute(CONDITIONALPARENTFIELD);
}
public String getConditionalParentValue() {
return getStringAttribute(CONDITIONALPARENTVALUE);
}
@Override
public MetadataType[] getChildTypes() {
return sNoChildren;
}
@Override
protected String getIdAttr() {
return FOREIGNKEYID;
}
@Override
protected void addAttributesToMap(Map attributeMap) {
attributeMap.put(FOREIGNKEYID, sAlphanum32);
attributeMap.put(PARENTRESOURCEID, sAlphanum32);
attributeMap.put(PARENTCLASSID, sAlphanum32);
attributeMap.put(PARENTSYSTEMNAME, sAlphanum32);
attributeMap.put(CHILDRESOURCEID, sAlphanum32);
attributeMap.put(CHILDCLASSID, sAlphanum32);
attributeMap.put(CHILDSYSTEMNAME, sAlphanum32);
attributeMap.put(CONDITIONALPARENTFIELD, retsname);
attributeMap.put(CONDITIONALPARENTVALUE, retsname);
}
}

View File

@ -0,0 +1,86 @@
package com.ossez.usreio.tests.common.metadata.types;
//import java.util.Date;
import java.util.Map;
import com.ossez.usreio.tests.common.metadata.MetaObject;
import com.ossez.usreio.tests.common.metadata.MetadataType;
public class MLookup extends MetaObject {
private static final MetadataType[] CHILDREN = { MetadataType.LOOKUP_TYPE };
private static final MLookupType[] EMPTYLOOKUPTYPES = {};
public static final String METADATAENTRYID = "MetadataEntryID";
public static final String LOOKUPNAME = "LookupName";
public static final String VISIBLENAME = "VisibleName";
public static final String VERSION = "Version";
public static final String DATE = "Date";
public static final String LOOKUPTYPEVERSION = "LookupTypeVersion";
public static final String LOOKUPTYPEDATE = "LookupTypeDate";
public MLookup() {
this(DEFAULT_PARSING);
}
public MLookup(boolean strictParsing) {
super(strictParsing);
}
public String getMetadataEntryID() {
return getStringAttribute(METADATAENTRYID);
}
public String getLookupName() {
return getStringAttribute(LOOKUPNAME);
}
public String getVisibleName() {
return getStringAttribute(VISIBLENAME);
}
public int getVersion() {
int ver = getIntAttribute(VERSION);
if (ver == 0){
ver = getIntAttribute(LOOKUPTYPEVERSION);
}
return ver;
}
public String getDate() {
String date = getDateAttribute(DATE);
if (date == null) {
date = getDateAttribute(LOOKUPTYPEDATE);
}
return date;
}
public MLookupType getMLookupType(String value) {
return (MLookupType) getChild(MetadataType.LOOKUP_TYPE, value);
}
public MLookupType[] getMLookupTypes() {
return (MLookupType[]) getChildren(MetadataType.LOOKUP_TYPE).toArray(EMPTYLOOKUPTYPES);
}
@Override
public MetadataType[] getChildTypes() {
return CHILDREN;
}
@Override
protected String getIdAttr() {
return LOOKUPNAME;
}
@Override
protected void addAttributesToMap(Map attributeMap) {
attributeMap.put(METADATAENTRYID, sAttrMetadataEntryId);
attributeMap.put(LOOKUPNAME, sAlphanum32);
attributeMap.put(VISIBLENAME, sPlaintext32);
attributeMap.put(VERSION, sAttrVersion);
attributeMap.put(DATE, sAttrDate);
attributeMap.put(LOOKUPTYPEVERSION, sAttrVersion);
attributeMap.put(LOOKUPTYPEDATE, sAttrDate);
}
}

View File

@ -0,0 +1,56 @@
package com.ossez.usreio.tests.common.metadata.types;
import java.util.Map;
import com.ossez.usreio.tests.common.metadata.MetaObject;
import com.ossez.usreio.tests.common.metadata.MetadataType;
public class MLookupType extends MetaObject {
public static final String METADATAENTRYID = "MetadataEntryID";
public static final String LONGVALUE = "LongValue";
public static final String SHORTVALUE = "ShortValue";
public static final String VALUE = "Value";
public MLookupType() {
this(DEFAULT_PARSING);
}
public MLookupType(boolean strictParsing) {
super(strictParsing);
}
public String getMetadataEntryID() {
return getStringAttribute(METADATAENTRYID);
}
public String getLongValue() {
return getStringAttribute(LONGVALUE);
}
public String getShortValue() {
return getStringAttribute(SHORTVALUE);
}
public String getValue() {
return getStringAttribute(VALUE);
}
@Override
public MetadataType[] getChildTypes() {
return sNoChildren;
}
@Override
protected String getIdAttr() {
return VALUE;
}
@Override
protected void addAttributesToMap(Map attributeMap) {
attributeMap.put(METADATAENTRYID, sAttrMetadataEntryId);
attributeMap.put(LONGVALUE, sText128);
attributeMap.put(SHORTVALUE, sText32);
attributeMap.put(VALUE, sAlphanum32);
}
}

View File

@ -0,0 +1,79 @@
package com.ossez.usreio.tests.common.metadata.types;
import java.util.Map;
import com.ossez.usreio.tests.common.metadata.MetaObject;
import com.ossez.usreio.tests.common.metadata.MetadataType;
public class MObject extends MetaObject {
public static final String METADATAENTRYID = "MetadataEntryID";
public static final String OBJECTTYPE = "ObjectType";
public static final String MIMETYPE = "MimeType";
public static final String VISIBLENAME = "VisibleName";
public static final String DESCRIPTION = "Description";
public static final String OBJECTTIMESTAMPNAME = "ObjectTimeStamp";
public static final String OBJECTCOUNT = "ObjectCount";
public static final String STANDARDNAME = "StandardName";
public MObject() {
this(DEFAULT_PARSING);
}
public MObject(boolean strictParsing) {
super(strictParsing);
}
public String getMetadataEntryID() {
return getStringAttribute(METADATAENTRYID);
}
public String getObjectType() {
return getStringAttribute(OBJECTTYPE);
}
public String getMIMEType() {
return getStringAttribute(MIMETYPE);
}
public String getVisibleName() {
return getStringAttribute(VISIBLENAME);
}
public String getDescription() {
return getStringAttribute(DESCRIPTION);
}
public String getStandardName() {
return getStringAttribute(STANDARDNAME);
}
@Override
public MetadataType[] getChildTypes() {
return sNoChildren;
}
@Override
protected String getIdAttr() {
return OBJECTTYPE;
}
@Override
protected void addAttributesToMap(Map attributeMap) {
attributeMap.put(METADATAENTRYID, sAlphanum24);
attributeMap.put(OBJECTTYPE, sAlphanum24);
attributeMap.put(MIMETYPE, sText64);
attributeMap.put(VISIBLENAME, sPlaintext64);
attributeMap.put(DESCRIPTION, sPlaintext128);
attributeMap.put(OBJECTTIMESTAMPNAME, retsname);
attributeMap.put(OBJECTCOUNT, retsname);
attributeMap.put(STANDARDNAME, retsname);
}
public String getObjectTimeStampName() {
return getStringAttribute(OBJECTTIMESTAMPNAME);
}
public String getObjectCount() {
return getStringAttribute(OBJECTCOUNT);
}
}

View File

@ -0,0 +1,270 @@
package com.ossez.usreio.tests.common.metadata.types;
//import java.util.Date;
import java.util.Map;
import com.ossez.usreio.tests.common.metadata.MetaObject;
import com.ossez.usreio.tests.common.metadata.MetadataType;
public class MResource extends MetaObject {
private static final MetadataType[] CHILDREN = {
MetadataType.VALIDATION_EXPRESSION,
MetadataType.LOOKUP,
MetadataType.CLASS,
MetadataType.OBJECT,
MetadataType.VALIDATION_EXTERNAL,
MetadataType.VALIDATION_LOOKUP,
MetadataType.EDITMASK,
MetadataType.UPDATE_HELP,
MetadataType.SEARCH_HELP
};
public static final String RESOURCEID = "ResourceID";
public static final String STANDARDNAME = "StandardName";
public static final String VISIBLENAME = "VisibleName";
public static final String DESCRIPTION = "Description";
public static final String KEYFIELD = "KeyField";
public static final String CLASSCOUNT = "ClassCount";
public static final String CLASSVERSION = "ClassVersion";
public static final String CLASSDATE = "ClassDate";
public static final String OBJECTVERSION = "ObjectVersion";
public static final String OBJECTDATE = "ObjectDate";
public static final String SEARCHHELPVERSION = "SearchHelpVersion";
public static final String SEARCHHELPDATE = "SearchHelpDate";
public static final String EDITMASKVERSION = "EditMaskVersion";
public static final String EDITMASKDATE = "EditMaskDate";
public static final String LOOKUPVERSION = "LookupVersion";
public static final String LOOKUPDATE = "LookupDate";
public static final String UPDATEHELPVERSION = "UpdateHelpVersion";
public static final String UPDATEHELPDATE = "UpdateHelpDate";
public static final String VALIDATIONEXPRESSIONVERSION = "ValidationExpressionVersion";
public static final String VALIDATIONEXPRESSIONDATE = "ValidationExpressionDate";
public static final String VALIDATIONLOOKUPVERSION = "ValidationLookupVersion";
public static final String VALIDATIONLOOKUPDATE = "ValidationLookupDate";
public static final String VALIDATIONEXTERNALVERSION = "ValidationExternalVersion";
public static final String VALIDATIONEXTERNALDATE = "ValidationExternalDate";
public MResource() {
this(DEFAULT_PARSING);
}
public MResource(boolean strictParsing) {
super(strictParsing);
}
public String getResourceID() {
return getStringAttribute(RESOURCEID);
}
public String getStandardName() {
return getStringAttribute(STANDARDNAME);
}
public String getVisibleName() {
return getStringAttribute(VISIBLENAME);
}
public String getDescription() {
return getStringAttribute(DESCRIPTION);
}
public String getKeyField() {
return getStringAttribute(KEYFIELD);
}
public int getClassCount() {
return getIntAttribute(CLASSCOUNT);
}
public int getClassVersion() {
return getIntAttribute(CLASSVERSION);
}
public String getClassDate() {
return getDateAttribute(CLASSDATE);
}
public int getObjectVersion() {
return getIntAttribute(OBJECTVERSION);
}
public String getObjectDate() {
return getDateAttribute(OBJECTDATE);
}
public int getSearchHelpVersion() {
return getIntAttribute(SEARCHHELPVERSION);
}
public String getSearchHelpDate() {
return getDateAttribute(SEARCHHELPDATE);
}
public int getEditMaskVersion() {
return getIntAttribute(EDITMASKVERSION);
}
public String getEditMaskDate() {
return getDateAttribute(EDITMASKDATE);
}
public int getLookupVersion() {
return getIntAttribute(LOOKUPVERSION);
}
public String getLookupDate() {
return getDateAttribute(LOOKUPDATE);
}
public int getUpdateHelpVersion() {
return getIntAttribute(UPDATEHELPVERSION);
}
public String getUpdateHelpDate() {
return getDateAttribute(UPDATEHELPDATE);
}
public int getValidationExpressionVersion() {
return getIntAttribute(VALIDATIONEXPRESSIONVERSION);
}
public String getValidationExpressionDate() {
return getDateAttribute(VALIDATIONEXPRESSIONDATE);
}
public int getValidationLookupVersion() {
return getIntAttribute(VALIDATIONLOOKUPVERSION);
}
public String getValidationLookupDate() {
return getDateAttribute(VALIDATIONLOOKUPDATE);
}
public int getValidationExternalVersion() {
return getIntAttribute(VALIDATIONEXTERNALVERSION);
}
public String getValidationExternalDate() {
return getDateAttribute(VALIDATIONEXTERNALDATE);
}
public MValidationExpression getMValidationExpression(String validationExpressionID) {
return (MValidationExpression) getChild(MetadataType.VALIDATION_EXPRESSION, validationExpressionID);
}
public MValidationExpression[] getMValidationExpressions() {
MValidationExpression[] tmpl = new MValidationExpression[0];
return (MValidationExpression[]) getChildren(MetadataType.VALIDATION_EXPRESSION).toArray(tmpl);
}
public MLookup getMLookup(String lookupName) {
return (MLookup) getChild(MetadataType.LOOKUP, lookupName);
}
public MLookup[] getMLookups() {
MLookup[] tmpl = new MLookup[0];
return (MLookup[]) getChildren(MetadataType.LOOKUP).toArray(tmpl);
}
public MClass getMClass(String className) {
return (MClass) getChild(MetadataType.CLASS, className);
}
public MClass[] getMClasses() {
MClass[] tmpl = new MClass[0];
return (MClass[]) getChildren(MetadataType.CLASS).toArray(tmpl);
}
public MObject getMObject(String objectType) {
return (MObject) getChild(MetadataType.OBJECT, objectType);
}
public MObject[] getMObjects() {
MObject[] tmpl = new MObject[0];
return (MObject[]) getChildren(MetadataType.OBJECT).toArray(tmpl);
}
public MValidationExternal getMValidationExternal(String validationExternalName) {
return (MValidationExternal) getChild(MetadataType.VALIDATION_EXTERNAL, validationExternalName);
}
public MValidationExternal[] getMValidationExternal() {
MValidationExternal[] tmpl = new MValidationExternal[0];
return (MValidationExternal[]) getChildren(MetadataType.VALIDATION_EXTERNAL).toArray(tmpl);
}
public MValidationLookup getMValidationLookup(String validationLookupName) {
return (MValidationLookup) getChild(MetadataType.VALIDATION_LOOKUP, validationLookupName);
}
public MValidationLookup[] getMValidationLookups() {
MValidationLookup[] tmpl = new MValidationLookup[0];
return (MValidationLookup[]) getChildren(MetadataType.VALIDATION_LOOKUP).toArray(tmpl);
}
public MEditMask getMEditMask(String editMaskID) {
return (MEditMask) getChild(MetadataType.EDITMASK, editMaskID);
}
public MEditMask[] getMEditMasks() {
MEditMask[] tmpl = new MEditMask[0];
return (MEditMask[]) getChildren(MetadataType.EDITMASK).toArray(tmpl);
}
public MUpdateHelp getMUpdateHelp(String updateHelpID) {
return (MUpdateHelp) getChild(MetadataType.UPDATE_HELP, updateHelpID);
}
public MUpdateHelp[] getMUpdateHelps() {
MUpdateHelp[] tmpl = new MUpdateHelp[0];
return (MUpdateHelp[]) getChildren(MetadataType.UPDATE_HELP).toArray(tmpl);
}
public MSearchHelp getMSearchHelp(String searchHelpID) {
return (MSearchHelp) getChild(MetadataType.SEARCH_HELP, searchHelpID);
}
public MSearchHelp[] getMSearchHelps() {
MSearchHelp[] tmpl = new MSearchHelp[0];
return (MSearchHelp[]) getChildren(MetadataType.SEARCH_HELP).toArray(tmpl);
}
@Override
public MetadataType[] getChildTypes() {
return CHILDREN;
}
@Override
protected String getIdAttr() {
return RESOURCEID;
}
@Override
protected void addAttributesToMap(Map attributeMap) {
attributeMap.put(RESOURCEID, sAlphanum32);
attributeMap.put(STANDARDNAME, sAlphanum32);
attributeMap.put(VISIBLENAME, sPlaintext32);
attributeMap.put(DESCRIPTION, sPlaintext64);
attributeMap.put(KEYFIELD, sAlphanum32);
attributeMap.put(CLASSCOUNT, sAttrNumeric);
attributeMap.put(CLASSVERSION, sAttrVersion);
attributeMap.put(CLASSDATE, sAttrDate);
attributeMap.put(OBJECTVERSION, sAttrVersion);
attributeMap.put(OBJECTDATE, sAttrDate);
attributeMap.put(SEARCHHELPVERSION, sAttrVersion);
attributeMap.put(SEARCHHELPDATE, sAttrDate);
attributeMap.put(EDITMASKVERSION, sAttrVersion);
attributeMap.put(EDITMASKDATE, sAttrDate);
attributeMap.put(LOOKUPVERSION, sAttrVersion);
attributeMap.put(LOOKUPDATE, sAttrDate);
attributeMap.put(UPDATEHELPVERSION, sAttrVersion);
attributeMap.put(UPDATEHELPDATE, sAttrDate);
attributeMap.put(VALIDATIONEXPRESSIONVERSION, sAttrVersion);
attributeMap.put(VALIDATIONEXPRESSIONDATE, sAttrDate);
attributeMap.put(VALIDATIONLOOKUPVERSION, sAttrVersion);
attributeMap.put(VALIDATIONLOOKUPDATE, sAttrDate);
attributeMap.put(VALIDATIONEXTERNALVERSION, sAttrVersion);
attributeMap.put(VALIDATIONEXTERNALDATE, sAttrDate);
}
}

View File

@ -0,0 +1,50 @@
package com.ossez.usreio.tests.common.metadata.types;
import java.util.Map;
import com.ossez.usreio.tests.common.metadata.MetaObject;
import com.ossez.usreio.tests.common.metadata.MetadataType;
public class MSearchHelp extends MetaObject {
public static final String METADATAENTRYID = "MetadataEntryID";
public static final String SEARCHHELPID = "SearchHelpID";
public static final String VALUE = "Value";
public MSearchHelp() {
this(DEFAULT_PARSING);
}
public MSearchHelp(boolean strictParsing) {
super(strictParsing);
}
public String getMetadataEntryID() {
return getStringAttribute(METADATAENTRYID);
}
public String getSearchHelpID() {
return getStringAttribute(SEARCHHELPID);
}
public String getValue() {
return getStringAttribute(VALUE);
}
@Override
public MetadataType[] getChildTypes() {
return sNoChildren;
}
@Override
protected String getIdAttr() {
return SEARCHHELPID;
}
@Override
protected void addAttributesToMap(Map attributeMap) {
attributeMap.put(METADATAENTRYID, sAttrMetadataEntryId);
attributeMap.put(SEARCHHELPID, sAlphanum32);
attributeMap.put(VALUE, sText1024);
}
}

View File

@ -0,0 +1,89 @@
package com.ossez.usreio.tests.common.metadata.types;
//import java.util.Date;
import java.util.Map;
import com.ossez.usreio.tests.common.metadata.MetaObject;
import com.ossez.usreio.tests.common.metadata.MetadataType;
public class MSystem extends MetaObject {
public static final String SYSTEMID = "SystemID";
public static final String SYSTEMDESCRIPTION = "SystemDescription";
public static final String COMMENTS = "Comments";
public static final String DATE = "Date";
public static final String VERSION = "Version";
public static final String TIMEZONEOFFSET = "TimeZoneOffset";
public MSystem() {
this(DEFAULT_PARSING);
}
public MSystem(boolean strictParsing) {
super(strictParsing);
}
public String getSystemID() {
return getStringAttribute(SYSTEMID);
}
public String getComment() {
return getStringAttribute(COMMENTS);
}
public String getSystemDescription() {
return getStringAttribute(SYSTEMDESCRIPTION);
}
public String getDate() {
return getDateAttribute(DATE);
}
public String getTimeZoneOffset() {
return getDateAttribute(TIMEZONEOFFSET);
}
public int getVersion() {
return getIntAttribute(VERSION);
}
public MResource getMResource(String resourceID) {
return (MResource) getChild(MetadataType.RESOURCE, resourceID);
}
public MResource[] getMResources() {
MResource[] tmpl = new MResource[0];
return (MResource[]) getChildren(MetadataType.RESOURCE).toArray(tmpl);
}
public MForeignKey getMForeignKey(String foreignKeyID) {
return (MForeignKey) getChild(MetadataType.FOREIGNKEYS, foreignKeyID);
}
public MForeignKey[] getMForeignKeys() {
MForeignKey[] tmpl = new MForeignKey[0];
return (MForeignKey[]) getChildren(MetadataType.FOREIGNKEYS).toArray(tmpl);
}
@Override
public MetadataType[] getChildTypes() {
return CHILDREN;
}
@Override
protected String getIdAttr() {
return null;
}
public static final MetadataType[] CHILDREN = { MetadataType.RESOURCE, MetadataType.FOREIGNKEYS };
@Override
protected void addAttributesToMap(Map attributeMap) {
attributeMap.put(SYSTEMID, sAlphanum10);
attributeMap.put(SYSTEMDESCRIPTION, sPlaintext64);
attributeMap.put(DATE, sAttrDate);
attributeMap.put(VERSION, sAttrVersion);
attributeMap.put(COMMENTS, sText);
attributeMap.put(TIMEZONEOFFSET, sAttrDate);
}
}

View File

@ -0,0 +1,242 @@
package com.ossez.usreio.tests.common.metadata.types;
import java.util.Map;
import com.ossez.usreio.tests.common.metadata.AttrType;
import com.ossez.usreio.tests.common.metadata.MetaObject;
import com.ossez.usreio.tests.common.metadata.MetadataType;
import com.ossez.usreio.tests.common.metadata.attrib.AttrEnum;
public class MTable extends MetaObject {
public static final String METADATAENTRYID = "MetadataEntryID";
public static final String SYSTEMNAME = "SystemName";
public static final String STANDARDNAME = "StandardName";
public static final String LONGNAME = "LongName";
public static final String DBNAME = "DBName";
public static final String SHORTNAME = "ShortName";
public static final String MAXIMUMLENGTH = "MaximumLength";
public static final String DATATYPE = "DataType";
public static final String PRECISION = "Precision";
public static final String SEARCHABLE = "Searchable";
public static final String INTERPRETATION = "Interpretation";
public static final String ALIGNMENT = "Alignment";
public static final String USESEPARATOR = "UseSeparator";
public static final String EDITMASKID = "EditMaskID";
public static final String LOOKUPNAME = "LookupName";
public static final String MAXSELECT = "MaxSelect";
public static final String UNITS = "Units";
public static final String INDEX = "Index";
public static final String MINIMUM = "Minimum";
public static final String MAXIMUM = "Maximum";
public static final String DEFAULT = "Default";
public static final String REQUIRED = "Required";
public static final String SEARCHHELPID = "SearchHelpID";
public static final String UNIQUE = "Unique";
public static final String MODTIMESTAMP = "ModTimeStamp";
public static final String MODTIMESTAMPNAME = "ModTimeStampName";
public static final String FOREIGNKEYNAME = "ForeignKeyName";
public static final String FOREIGNFIELD = "ForeignField";
public static final String INKEYINDEX = "InKeyIndex";
public static final String KEYQUERY = "KeyQuery";
public static final String KEYSELECT = "KeySelect";
private static final String[] DATATYPES = "Boolean,Character,Date,DateTime,Time,Tiny,Small,Int,Long,Decimal".split(",");
private static final AttrType sDataTypes = new AttrEnum(DATATYPES);
private static final String[] INTERPRETATIONS = "Number,Currency,Lookup,LookupMulti,LookupBitstring,LookupBitmask".split(",");
private static final AttrType sInterpretations = new AttrEnum(INTERPRETATIONS);
private static final String[] ALIGNMENTS = "Left,Right,Center,Justify".split(",");
private static final AttrType sAlignments = new AttrEnum(ALIGNMENTS);
private static final String[] UNITSS = "Feet,Meters,SqFt,SqMeters,Acres,Hectares".split(",");
private static final AttrType sUnits = new AttrEnum(UNITSS);
public MTable() {
this(DEFAULT_PARSING);
}
public MTable(boolean strictParsing) {
super(strictParsing);
}
public String getMetadataEntryID() {
String metadataEntryID = getStringAttribute(METADATAENTRYID);
if (metadataEntryID == null){
metadataEntryID = this.getSystemName();
}
return metadataEntryID;
}
public String getSystemName() {
return getStringAttribute(SYSTEMNAME);
}
public String getStandardName() {
return getStringAttribute(STANDARDNAME);
}
public String getLongName() {
return getStringAttribute(LONGNAME);
}
public String getDBName() {
return getStringAttribute(DBNAME);
}
public String getShortName() {
return getStringAttribute(SHORTNAME);
}
public int getMaximumLength() {
return getIntAttribute(MAXIMUMLENGTH);
}
public String getDataType() {
return getStringAttribute(DATATYPE);
}
public int getPrecision() {
return getIntAttribute(PRECISION);
}
public boolean getSearchable() {
return getBooleanAttribute(SEARCHABLE);
}
public String getInterpretation() {
return getStringAttribute(INTERPRETATION);
}
public boolean isLookup() {
String interp = getInterpretation();
if (interp != null && interp.startsWith("Lookup")) {
return true;
}
if (getSystemName().equalsIgnoreCase("status")) {
System.out.println("Field is " + getSystemName() + " and interp " + "is " + interp
+ " but isLookup() is false");
}
return false;
}
public String getAlignment() {
return getStringAttribute(ALIGNMENT);
}
public boolean getUseSeparator() {
return getBooleanAttribute(USESEPARATOR);
}
public String getEditMaskID() {
return getStringAttribute(EDITMASKID);
}
public String getLookupName() {
return getStringAttribute(LOOKUPNAME);
}
public int getMaxSelect() {
return getIntAttribute(MAXSELECT);
}
public String getUnits() {
return getStringAttribute(UNITS);
}
public int getIndex() {
return getIntAttribute(INDEX);
}
public int getMinimum() {
return getIntAttribute(MINIMUM);
}
public int getMaximum() {
return getIntAttribute(MAXIMUM);
}
public int getDefault() {
return getIntAttribute(DEFAULT);
}
public int getRequired() {
return getIntAttribute(REQUIRED);
}
public String getSearchHelpID() {
return getStringAttribute(SEARCHHELPID);
}
public boolean getUnique() {
return getBooleanAttribute(UNIQUE);
}
public boolean getModTimestamp() {
return getBooleanAttribute(MODTIMESTAMP);
}
public boolean getModTimestampName() {
return getBooleanAttribute(MODTIMESTAMPNAME);
}
public boolean getInKeyIndex() {
return getBooleanAttribute(INKEYINDEX);
}
@Override
public MetadataType[] getChildTypes() {
return sNoChildren;
}
@Override
protected String getIdAttr() {
return SYSTEMNAME;
}
@Override
protected void addAttributesToMap(Map attributeMap) {
attributeMap.put(METADATAENTRYID, retsid);
attributeMap.put(SYSTEMNAME, retsname);
attributeMap.put(STANDARDNAME, retsname);
attributeMap.put(LONGNAME, sText256);
attributeMap.put(DBNAME, sAlphanum10);
attributeMap.put(SHORTNAME, sText64);
attributeMap.put(MAXIMUMLENGTH, sAttrNumericPositive);
attributeMap.put(DATATYPE, sDataTypes);
attributeMap.put(PRECISION, sAttrNumeric);
attributeMap.put(SEARCHABLE, sAttrBoolean);
attributeMap.put(INTERPRETATION, sInterpretations);
attributeMap.put(ALIGNMENT, sAlignments);
attributeMap.put(USESEPARATOR, sAttrBoolean);
// XXX: but multiples are separated by commas
attributeMap.put(EDITMASKID, retsname);
attributeMap.put(LOOKUPNAME, retsname);
attributeMap.put(MAXSELECT, sAttrNumeric);
attributeMap.put(UNITS, sUnits);
attributeMap.put(INDEX, sAttrNumeric);
attributeMap.put(MINIMUM, sAttrNumeric);
attributeMap.put(MAXIMUM, sAttrNumeric);
// XXX: serial
attributeMap.put(DEFAULT, sAttrNumeric);
attributeMap.put(REQUIRED, sAttrNumeric);
attributeMap.put(SEARCHHELPID, retsname);
attributeMap.put(UNIQUE, sAttrBoolean);
attributeMap.put(MODTIMESTAMP, sAttrBoolean);
attributeMap.put(MODTIMESTAMPNAME, retsname);
attributeMap.put(FOREIGNKEYNAME,retsid);
attributeMap.put(FOREIGNFIELD,retsname);
attributeMap.put(INKEYINDEX, sAttrBoolean);
attributeMap.put(KEYQUERY, sAttrBoolean);
attributeMap.put(KEYSELECT, sAttrBoolean);
}
public String getForeignKeyName() {
return getStringAttribute(FOREIGNKEYNAME);
}
public String getForeignField() {
return getStringAttribute(FOREIGNFIELD);
}
}

Some files were not shown because too many files have changed in this diff Show More