/* See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* Esri Inc. licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.esri.gpt.control.rest.writer;
import java.io.IOException;
import java.io.Writer;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.Map;
import java.util.TreeMap;
import com.esri.gpt.control.rest.repositories.RepositoriesResultSet;
import com.esri.gpt.control.rest.repositories.RepositoriesResultSetWrapper;
import com.esri.gpt.framework.util.Val;
/**
* Super-class for a rest response writer based upon a JDBC ResultSet.
*/
public abstract class ResultSetWriter extends ResponseWriter {
/** constructors ============================================================ */
/**
* Constructs with an underlying response writer.
* @param underlyingWriter the underlying writer
*/
public ResultSetWriter(Writer underlyingWriter) {
super(underlyingWriter);
}
/** methods ================================================================= */
/**
* Ends a row.
* @param depth the indent depth
* @throws IOException if an I/O exception occurs
*/
public abstract void endRow(int depth) throws IOException;
/**
* Ends a collection of rows.
* @param depth the indent depth
* @throws IOException if an I/O exception occurs
*/
public abstract void endRows(int depth) throws IOException;
/**
* Starts a row.
* @param depth the indent depth
* @throws IOException if an I/O exception occurs
*/
public abstract void startRow(int depth) throws IOException;
/**
* Starts a collection of rows.
* @param depth the indent depth
* @throws IOException if an I/O exception occurs
*/
public abstract void startRows(int depth) throws IOException;
/**
* Writes a cell property value.
* @param name the property name
* @param value the property value
* @param depth the indent depth
* @throws IOException if an I/O exception occurs
*/
public abstract void writeCell(String name, Object value, int depth) throws IOException;
/**
* Writes a ResultSet to the response.
*
*
*
* @param rs the ResultSet
* @param depth the indent depth
* @param columnTags optional, the tag names per column
* @throws IOException if an I/O exception occurs
* @throws SQLException if an SQL exception occurs
*/
public void writeResultSet(ResultSet rs, int depth, String[] columnTags)
throws IOException, SQLException {
if(rs instanceof RepositoriesResultSet) {
writeResultSet1(rs, depth, columnTags);
return;
}
this.startRows(depth);
ResultSetMetaData md = rs.getMetaData();
int nColumns = md.getColumnCount();
while (rs.next()) {
this.startRow(depth+1);
for (int i=1;i<=nColumns;i++) {
String name = md.getColumnName(i);
if (columnTags != null) {
name = columnTags[i-1];
}
this.writeCell(name,rs.getObject(i),depth+2);
}
this.endRow(depth+1);
}
this.endRows(depth);
}
/**
* Writes a ResultSet to the response.
*
* 1.2.5 changed to combine values with gpt.xml.
*
* @param rs the ResultSet
* @param depth the indent depth
* @param columnTags optional, the tag names per column
* @throws IOException if an I/O exception occurs
* @throws SQLException if an SQL exception occurs
*/
private void writeResultSet1(ResultSet rs, int depth, String[] columnTags)
throws IOException, SQLException {
//this.startRows(depth);
Map<String, LinkedList<RecordElement>> mapIds =
new TreeMap<String, LinkedList<RecordElement>>(String.CASE_INSENSITIVE_ORDER);
LinkedList<RecordElement> repLocal = null;
LinkedList<RecordElement> repAgs = null;
while (rs.next()) {
ResultSetMetaData md = rs.getMetaData();// T.M. needed for ResultSetWrapper
int nColumns = md.getColumnCount();
//this.startRow(depth+1);
LinkedList<RecordElement> lre =
new LinkedList<ResultSetWriter.RecordElement>();
String repositoryName = null;
String repositoryId = null;
for (int i=1;i<=nColumns;i++) {
String name = md.getColumnName(i);
boolean isIteratingDb = true;
if (rs instanceof RepositoriesResultSetWrapper) {
RepositoriesResultSetWrapper reposRs = (RepositoriesResultSetWrapper) rs;
isIteratingDb = reposRs == null
|| (reposRs != null && reposRs.isDbFinishedIterating() == false);
}
if (isIteratingDb && columnTags != null) {
name = columnTags[i-1];
}
if(Val.chkStr(name).toLowerCase().equals("id")) {
repositoryId = rs.getObject(i).toString();
}
if(Val.chkStr(name).toLowerCase().equals("name")) {
repositoryName = rs.getObject(i).toString();
}
RecordElement re =
new RecordElement(name, rs.getObject(i), depth+2);
lre.push(re);
//this.writeCell(name,rs.getObject(i),depth+2);
}
if(nColumns < 1) {
// ignore
} else if(Val.chkStr(repositoryId).equals("local")) {
repLocal = lre;
} else if(Val.chkStr(repositoryId).equals("arcgis.com")) {
repAgs = lre;
mapIds.put(repositoryName, lre);
} else if(repositoryName != null) {
mapIds.put(repositoryName, lre);
}
//this.endRow(depth+1);
}
//this.endRows(depth);
this.startRows(depth);
if(repLocal != null) {
mapIds.remove("local");
writeResultSetRecord(repLocal, depth);
}
if(repAgs != null) {
//mapIds.remove("arcgis.com");
//writeResultSetRecord(repAgs, depth);
}
Iterator<String> iter = mapIds.keySet().iterator();
while(iter.hasNext()) {
String key = iter.next();
LinkedList<RecordElement> rep = mapIds.get(key);
writeResultSetRecord(rep, depth);
}
this.endRows(depth);
}
private void writeResultSetRecord(LinkedList<RecordElement> lre, int depth)
throws IOException {
this.startRow(depth+1);
Iterator<RecordElement> iter = lre.iterator();
while(iter.hasNext()) {
RecordElement re = iter.next();
this.writeCell(re.name,re.object,depth+2);
}
this.endRow(depth+1);
}
private class RecordElement {
private String name;
private Object object;
private int depth;
private RecordElement(String name, Object obj, int depth) {
this.name = name;
this.object = obj;
this.depth = depth;
}
}
}