Möjligheten att anropa java från adaptrarna erbjuder en hel del flexibilitet, inklusive möjligheten att anropa din egen JDBC-lagrade proc-implementering. Genom att använda detta kan vi anropa de lagrade processerna med OUT SYS_REFCURSOR definierade och få resultatet satt tillbaka som JSON. En jdbc-datakälla måste skapas på din appserver (Liberty, Websphere, etc..) Se metoderna som refereras till i StoredProcedure java-klassen för att exekvera den lagrade processen och få tillbaka data som JSON. Använder Apache dbutils och Jackson för JSON-grejer.
CREATE PACKAGE "HR"."HR_DATA" IS -- Declare types, variables, constants, exceptions, cursors,
-- and subprograms that can be referenced from outside the package.
PROCEDURE "GETCURSORS" (
"DEP_ID" IN NUMBER,
"EMPLOYEES_C" OUT SYS_REFCURSOR,
"DEPENDENTS_C" OUT SYS_REFCURSOR);
END "HR_DATA";
Adapterkod:
function getEmployeesByDep(departmentId){
var storedProcedure = new Packages.com.samnunnally.dao.StoredProcedure();
storedProcedure.setDataSource("jdbc/hr_datasource");
storedProcedure.setStoredProcName("HR.HR_DATA");
storedProcedure.addParameter(0, departmentId, false);
storedProcedure.addOutParameter(1, Packages.oracle.jdbc.OracleTypes.CURSOR);
storedProcedure.addOutParameter(2, Packages.oracle.jdbc.OracleTypes.CURSOR);
var rsHandler = new Packages.org.apache.commons.dbutils.handlers.MapListHandler();
storedProcedure.execute(rsHandler);
return {
result :
{
EMPLOYEES : storedProcedure.getJsonParameterValue(1),
DEPENDENTS : storedProcedure.getJsonParameterValue(2)
}
};
}
Java JDBC-klass:
package com.samnunnally.dao;
import java.io.IOException;
import java.sql.CallableStatement;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Types;
import java.util.ArrayList;
import javax.naming.Context;
import javax.naming.InitialContext;
import javax.naming.NamingException;
import javax.sql.DataSource;
import org.apache.commons.dbutils.ResultSetHandler;
import org.apache.commons.dbutils.handlers.KeyedHandler;
import org.codehaus.jackson.JsonGenerationException;
import org.codehaus.jackson.annotate.JsonProperty;
import org.codehaus.jackson.annotate.JsonRawValue;
import org.codehaus.jackson.map.JsonMappingException;
import org.codehaus.jackson.map.ObjectMapper;
/**
* @author Sam Nunnally
*
*/
public class StoredProcedure {
private String dataSource = "";
private String storedProcName = "";
private ArrayList<Parameter> parameters = null;
private Object resultSet = null;
private boolean autoCommit = true;
private final static String CALL_STRING = "{call ";
private final static String CALL_OPEN_PAREN = "(";
private final static String CALL_PARM = "?";
private final static String CALL_COMMA = ",";
private final static String CALL_CLOSE = ")}";
private class Parameter{
private int index = -1;
private boolean outParamter = false;
private Object value = null;
private Integer type = null;
/**
* @return the index
*/
public int getIndex() {
return index;
}
/**
* @param index the index to set
*/
public void setIndex(int index) {
this.index = index;
}
/**
* @return the outParamter
*/
public boolean isOutParamter() {
return outParamter;
}
/**
* @param outParamter the outParamter to set
*/
public void setOutParamter(boolean outParamter) {
this.outParamter = outParamter;
}
/**
* @return the value
*/
public Object getValue() {
return value;
}
/**
* @param value the value to set
*/
public void setValue(Object value) {
this.value = value;
}
/**
* @return the type
*/
public int getType() {
return type;
}
/**
* @param type the type to set
*/
public void setType(int type) {
this.type = type;
}
}
public void execute() throws NamingException, SQLException{
this.execute(new KeyedHandler<Object>());
}
public void execute(ResultSetHandler<?> rsHandler) throws NamingException, SQLException{
Connection connection = null;
try {
Context ctx = new InitialContext();
DataSource ds = (DataSource)ctx.lookup(dataSource);
connection = ds.getConnection();
connection.setAutoCommit(autoCommit);
String call = createCallString();
CallableStatement cs = connection.prepareCall(call);
int i=1;
for (Parameter p : this.getParameters()) {
if(p.isOutParamter()){
cs.registerOutParameter(i, p.getType());
}
else{
cs.setObject(i, p.getValue());
}
i++;
}
cs.execute();
i=1;
for (Parameter p : this.getParameters()) {
if(p.isOutParamter()){
if(p.getType() == -10/*oracle.jdbc.OracleTypes.CURSOR*/){
p.setValue(rsHandler.handle((ResultSet)cs.getObject(i)));
}
else{
p.setValue(cs.getObject(i));
}
}
i++;
}
/*
* Could do some BeanHandler implementation for <T> T
*
Class Summary
AbstractKeyedHandler<K,V> ResultSetHandler implementation that returns a Map.
AbstractListHandler<T> Abstract class that simplify development of ResultSetHandler classes that convert ResultSet into List.
ArrayHandler ResultSetHandler implementation that converts a ResultSet into an Object[].
ArrayListHandler ResultSetHandler implementation that converts the ResultSet into a List of Object[]s.
BeanHandler<T> ResultSetHandler implementation that converts the first ResultSet row into a JavaBean.
BeanListHandler<T> ResultSetHandler implementation that converts a ResultSet into a List of beans.
BeanMapHandler<K,V> ResultSetHandler implementation that returns a Map of Beans.
ColumnListHandler<T> ResultSetHandler implementation that converts one ResultSet column into a List of Objects.
KeyedHandler<K> ResultSetHandler implementation that returns a Map of Maps.
MapHandler ResultSetHandler implementation that converts the first ResultSet row into a Map.
MapListHandler ResultSetHandler implementation that converts a ResultSet into a List of Maps.
ScalarHandler<T> ResultSetHandler implementation that converts one ResultSet column into an Object.
*/
ResultSet rs = cs.getResultSet();
if(rs != null){
resultSet = rsHandler.handle(rs);
}
}
finally{
if(connection != null){
connection.close();
}
}
}
private String createCallString(){
StringBuffer sb = new StringBuffer();
int parmCnt = this.getParameters().size();
sb.append(CALL_STRING)
.append(storedProcName)
.append(CALL_OPEN_PAREN);
for(int i = 0;i<parmCnt;i++){
sb.append(CALL_PARM);
if(parmCnt > i + 1){
sb.append(CALL_COMMA);
}
}
sb.append(CALL_CLOSE);
return sb.toString();
}
/**
* @return the dataSource
*/
public String getDataSource() {
return dataSource;
}
/**
* @param dataSource the dataSource to set
*/
public void setDataSource(final String dataSource) {
this.dataSource = dataSource;
}
/**
* @return the storedProc
*/
public String getStoredProcName() {
return storedProcName;
}
/**
* @param storedProc the storedProc to set
*/
public void setStoredProcName(final String storedProcName) {
this.storedProcName = storedProcName;
}
/**
* @return the autoCommit
*/
public boolean isAutoCommit() {
return autoCommit;
}
/**
* @param autoCommit the autoCommit to set
*/
public void setAutoCommit(boolean autoCommit) {
this.autoCommit = autoCommit;
}
/**
* @return the resultSet
*/
public Object getResultSet() {
return resultSet;
}
/**
* @return the parameters
*/
private ArrayList<Parameter> getParameters() {
if(parameters == null){
parameters = new ArrayList<StoredProcedure.Parameter>();
}
return parameters;
}
/**
* @param index - the first parameter is 0, the second is 1, and so on
* @param value
* @param isOutParam
*/
public void addParameter(int index, Object value, boolean isOutParam){
Parameter p = new Parameter();
p.setIndex(index);
p.setValue(value);
p.setOutParamter(isOutParam);
p.setType(determineSqlType(value));
this.getParameters().add(index, p);
}
/**
* @param index - the first parameter is 0, the second is 1, and so on
* @param type - java.sql.Types int value of the parameter
*/
public void addOutParameter(int index, int type){
Parameter p = new Parameter();
p.setIndex(index);
p.setType(type);
p.setOutParamter(true);
this.getParameters().add(index, p);
}
/**
* @param index - the first parameter is 0, the second is 1, and so on
* @param type - java.sql.Types value of the parameter
*/
public void addOutParameter(int index, Object type){
Parameter p = new Parameter();
p.setIndex(index);
p.setType((int)type);
p.setOutParamter(true);
this.getParameters().add(index, p);
}
public Object getParameter(int index){
return this.getParameters().get(index);
}
@JsonProperty("raw")
@JsonRawValue
public String getJsonResultSet() throws JsonGenerationException, JsonMappingException, IOException{
String result = "{}";
if(this.getResultSet() != null){
ObjectMapper mapper = new ObjectMapper();
result = mapper.writeValueAsString(this.getResultSet());
}
return result;
}
@JsonProperty("raw")
@JsonRawValue
public String getJsonParameterValue(int index) throws JsonGenerationException, JsonMappingException, IOException{
String result = "{}";
Parameter parm = this.getParameters().get(index);
if(parm != null && parm.getValue() != null){
ObjectMapper mapper = new ObjectMapper();
result = mapper.writeValueAsString(parm.getValue());
}
return result;
}
/**
*
* Determines SqlType of object. throws exception if unknown
*
* NOTE: this is not meant to be a complete list, just picked most
* common types to start with.
*
* @param obj
*
* @return $returnType
*
*/
public static int determineSqlType(Object obj) {
int sqlType = Types.VARCHAR;
if (obj == null) {
// assuming a string if object is null
sqlType = Types.VARCHAR;
} else if (obj instanceof java.lang.String) {
sqlType = Types.VARCHAR;
} else if (obj instanceof java.lang.Integer) {
sqlType = Types.INTEGER;
} else if (obj instanceof java.lang.Double) {
sqlType = Types.DOUBLE;
} else if (obj instanceof java.lang.Float) {
sqlType = Types.FLOAT;
} else if (obj instanceof java.io.InputStream) {
sqlType = Types.LONGVARBINARY;
} else if (obj instanceof java.math.BigDecimal) {
sqlType = Types.DECIMAL;
} else if (obj instanceof java.math.BigInteger) {
sqlType = Types.BIGINT;
} else if (obj instanceof java.util.Date) {
sqlType = Types.DATE;
} else if (obj instanceof java.sql.Date) {
sqlType = Types.DATE;
} else if (obj instanceof java.sql.Timestamp) {
sqlType = Types.TIMESTAMP;
} else if (obj instanceof java.sql.ResultSet) {
//oracle.jdbc.OracleTypes.CURSOR
sqlType = -10;
} else if (obj instanceof java.sql.Blob) {
sqlType = Types.BLOB;
} else if (obj instanceof java.sql.Clob) {
sqlType = Types.CLOB;
} else {
sqlType = Types.OTHER;
}
return sqlType;
}
}