USRE-88 Push new file for example
This commit is contained in:
parent
4d8d8fbee7
commit
42e924952d
|
@ -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>
|
|
@ -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;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -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);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -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());
|
||||||
|
}
|
||||||
|
}
|
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -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();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -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();
|
||||||
|
}
|
||||||
|
}
|
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -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);
|
||||||
|
}
|
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
|
@ -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;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -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;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -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
|
||||||
|
}
|
|
@ -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();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
|
@ -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();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,7 @@
|
||||||
|
package com.ossez.usreio.client;
|
||||||
|
|
||||||
|
public class InvalidArgumentException extends RetsException {
|
||||||
|
public InvalidArgumentException(String message) {
|
||||||
|
super(message);
|
||||||
|
}
|
||||||
|
}
|
|
@ -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+"'");
|
||||||
|
}
|
||||||
|
}
|
|
@ -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;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -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;
|
||||||
|
}
|
|
@ -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);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -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";
|
||||||
|
}
|
|
@ -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;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,9 @@
|
||||||
|
package com.ossez.usreio.client;
|
||||||
|
|
||||||
|
public class LogoutRequest extends VersionInsensitiveRequest {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setUrl(CapabilityUrls urls) {
|
||||||
|
setUrl(urls.getLogoutUrl());
|
||||||
|
}
|
||||||
|
}
|
|
@ -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;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -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);
|
||||||
|
}
|
|
@ -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);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -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);
|
||||||
|
}
|
|
@ -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
|
||||||
|
}
|
||||||
|
}
|
|
@ -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");
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -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;
|
||||||
|
|
||||||
|
}
|
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
|
@ -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);
|
||||||
|
|
||||||
|
}
|
|
@ -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);
|
||||||
|
|
||||||
|
}
|
|
@ -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;
|
||||||
|
|
||||||
|
}
|
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
|
@ -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);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -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);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -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();
|
||||||
|
}
|
|
@ -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();
|
||||||
|
}
|
|
@ -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);
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
|
@ -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;
|
||||||
|
}
|
|
@ -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;
|
||||||
|
}
|
|
@ -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;
|
||||||
|
}
|
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
|
@ -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;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -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
|
||||||
|
}
|
||||||
|
}
|
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
|
@ -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);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
|
@ -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;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
|
@ -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 + ")");
|
||||||
|
}
|
||||||
|
}
|
|
@ -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");
|
||||||
|
}
|
||||||
|
}
|
|
@ -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 + ")");
|
||||||
|
}
|
||||||
|
}
|
|
@ -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");
|
||||||
|
}
|
||||||
|
}
|
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
|
@ -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;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
@ -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);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
|
@ -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);
|
||||||
|
}
|
|
@ -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;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -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);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -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;
|
||||||
|
}
|
|
@ -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();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
|
@ -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));
|
||||||
|
}
|
||||||
|
}
|
|
@ -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;
|
||||||
|
}
|
|
@ -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;}
|
||||||
|
|
||||||
|
}
|
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
|
@ -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;
|
||||||
|
|
||||||
|
}
|
|
@ -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;
|
||||||
|
|
||||||
|
}
|
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
|
@ -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");
|
||||||
|
}
|
|
@ -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;
|
||||||
|
}
|
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
|
@ -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);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -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);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -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);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -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);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -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);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -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);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -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);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -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);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -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);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -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
Loading…
Reference in New Issue