/******************************************************************************* | |
* Copyright (c) 1998, 2013 Oracle and/or its affiliates. All rights reserved. | |
* This program and the accompanying materials are made available under the | |
* terms of the Eclipse Public License v1.0 and Eclipse Distribution License v. 1.0 | |
* which accompanies this distribution. | |
* The Eclipse Public License is available at http://www.eclipse.org/legal/epl-v10.html | |
* and the Eclipse Distribution License is available at | |
* http://www.eclipse.org/org/documents/edl-v10.php. | |
* | |
* Contributors: | |
* Oracle - initial API and implementation from Oracle TopLink | |
******************************************************************************/ | |
package org.eclipse.persistence.internal.xr; | |
// Javase imports | |
import java.io.ByteArrayOutputStream; | |
import java.io.IOException; | |
import java.io.InputStream; | |
import java.lang.reflect.Constructor; | |
import java.lang.reflect.Method; | |
import java.security.AccessController; | |
import java.sql.Blob; | |
import java.sql.Date; | |
import java.sql.Time; | |
import java.sql.Timestamp; | |
import java.util.ArrayList; | |
import java.util.Calendar; | |
import java.util.Vector; | |
import java.util.List; | |
import org.w3c.dom.Element; | |
// Java extension imports | |
import javax.activation.DataHandler; | |
import javax.xml.namespace.QName; | |
// EclipseLink imports | |
import org.eclipse.persistence.descriptors.ClassDescriptor; | |
import org.eclipse.persistence.exceptions.DescriptorException; | |
import org.eclipse.persistence.exceptions.DBWSException; | |
import org.eclipse.persistence.internal.databaseaccess.DatasourceCall; | |
import org.eclipse.persistence.internal.databaseaccess.OutputParameterForCallableStatement; | |
import org.eclipse.persistence.internal.descriptors.InstantiationPolicy; | |
import org.eclipse.persistence.internal.helper.ClassConstants; | |
import org.eclipse.persistence.internal.helper.DatabaseField; | |
import org.eclipse.persistence.internal.helper.Helper; | |
import org.eclipse.persistence.internal.jpa.JPAQuery; | |
import org.eclipse.persistence.internal.oxm.XMLConversionManager; | |
import org.eclipse.persistence.internal.oxm.conversion.Base64; | |
import org.eclipse.persistence.internal.security.PrivilegedAccessHelper; | |
import org.eclipse.persistence.internal.security.PrivilegedClassForName; | |
import org.eclipse.persistence.internal.security.PrivilegedGetConstructorFor; | |
import org.eclipse.persistence.internal.security.PrivilegedGetDeclaredMethod; | |
import org.eclipse.persistence.internal.security.PrivilegedInvokeConstructor; | |
import org.eclipse.persistence.internal.security.PrivilegedMethodInvoker; | |
import org.eclipse.persistence.internal.sessions.AbstractRecord; | |
import org.eclipse.persistence.internal.sessions.AbstractSession; | |
import org.eclipse.persistence.internal.sessions.DatabaseSessionImpl; | |
import org.eclipse.persistence.internal.xr.sxf.SimpleXMLFormat; | |
import org.eclipse.persistence.internal.xr.sxf.SimpleXMLFormatModel; | |
import org.eclipse.persistence.mappings.AttributeAccessor; | |
import org.eclipse.persistence.mappings.DatabaseMapping; | |
import org.eclipse.persistence.mappings.structures.ObjectRelationalDatabaseField; | |
import org.eclipse.persistence.oxm.NamespaceResolver; | |
import org.eclipse.persistence.oxm.XMLDescriptor; | |
import org.eclipse.persistence.oxm.XMLRoot; | |
import org.eclipse.persistence.oxm.mappings.XMLBinaryDataMapping; | |
import org.eclipse.persistence.oxm.mappings.XMLDirectMapping; | |
import org.eclipse.persistence.oxm.mappings.XMLFragmentCollectionMapping; | |
import org.eclipse.persistence.oxm.schema.XMLSchemaReference; | |
import org.eclipse.persistence.oxm.schema.XMLSchemaURLReference; | |
import org.eclipse.persistence.queries.DataReadQuery; | |
import org.eclipse.persistence.queries.DatabaseQuery; | |
import org.eclipse.persistence.queries.ReadObjectQuery; | |
import org.eclipse.persistence.sessions.DatabaseRecord; | |
import org.eclipse.persistence.sessions.Session; | |
import static org.eclipse.persistence.internal.helper.ClassConstants.STRING; | |
import static org.eclipse.persistence.internal.oxm.Constants.INT_QNAME; | |
import static org.eclipse.persistence.internal.xr.Util.DEFAULT_ATTACHMENT_MIMETYPE; | |
import static org.eclipse.persistence.internal.xr.sxf.SimpleXMLFormat.DEFAULT_SIMPLE_XML_FORMAT_TAG; | |
import static org.eclipse.persistence.internal.xr.sxf.SimpleXMLFormat.DEFAULT_SIMPLE_XML_TAG; | |
import static org.eclipse.persistence.internal.xr.Util.sqlToXmlName; | |
import static org.eclipse.persistence.internal.xr.Util.EMPTY_STR; | |
import static org.eclipse.persistence.internal.xr.Util.SLASH_CHAR; | |
import static org.eclipse.persistence.internal.xr.Util.SXF_QNAME; | |
import static org.eclipse.persistence.internal.xr.Util.TEMP_DOC; | |
import static org.eclipse.persistence.oxm.XMLConstants.BASE_64_BINARY_QNAME; | |
import static org.eclipse.persistence.oxm.XMLConstants.DATE_QNAME; | |
import static org.eclipse.persistence.oxm.XMLConstants.DATE_TIME_QNAME; | |
import static org.eclipse.persistence.oxm.XMLConstants.SCHEMA_INSTANCE_URL; | |
import static org.eclipse.persistence.oxm.XMLConstants.SCHEMA_URL; | |
import static org.eclipse.persistence.oxm.XMLConstants.TIME_QNAME; | |
import static org.eclipse.persistence.oxm.XMLConstants.XMLNS_URL; | |
/** | |
* <p><b>INTERNAL:</b>An XR QueryOperation is an executable representation of a <tt>SELECT</tt> | |
* operation on the database. | |
* | |
* @author Mike Norman - michael.norman@oracle.com | |
* @since EclipseLink 1.x | |
*/ | |
@SuppressWarnings({"serial", "unchecked"/*, "rawtypes"*/}) | |
public class QueryOperation extends Operation { | |
public static final String ORACLESQLXML_STR = "oracle.jdbc.driver.OracleSQLXML"; | |
public static final String ORACLEOPAQUE_STR = "oracle.sql.OPAQUE"; | |
protected static final String RESULT_STR = "result"; | |
protected static final String XMLTYPEFACTORY_STR = "org.eclipse.persistence.internal.platform.database.oracle.xdb.XMLTypeFactoryImpl"; | |
protected static final String GETSTRING_METHOD = "getString"; | |
protected static final String ATTACHMENT_STR = "/attachment"; | |
protected static final String CURSOR_OF_STR = "cursor of "; | |
protected static final String DATAHANDLER_STR = "DataHandler"; | |
protected static final String RESULTS_STR = "results"; | |
protected static final String VALUEOBJECT_STR = "ValueObject"; | |
protected static final String VALUE_STR = "value"; | |
protected static final String SIMPLEXML_FORMAT_STR = "/simple-xml-format"; | |
protected static final String SIMPLEXML_STR = "simpleXML"; | |
protected static final String DATABASEQUERY_STR = "databasequery"; | |
protected static final String ITEMS_STR = "ITEMS"; | |
protected static final String XSD_STR = "xmlns:xsd"; | |
protected static final String XSI_STR = "xmlns:xsi"; | |
protected static final String XSITYPE_STR = "xsi:type"; | |
protected static final String BASE64_BINARY_STR = "xsd:base64Binary"; | |
protected Result result; | |
protected QueryHandler queryHandler; | |
protected boolean userDefined = true; | |
public QueryOperation() { | |
super(); | |
} | |
public Result getResult() { | |
return result; | |
} | |
public void setResult(Result result) { | |
this.result = result; | |
} | |
public QueryHandler getQueryHandler() { | |
return queryHandler; | |
} | |
public void setQueryHandler(QueryHandler queryHandler) { | |
this.queryHandler = queryHandler; | |
} | |
public boolean isUserDefined() { | |
return userDefined; | |
} | |
public void setUserDefined(boolean userDefined) { | |
this.userDefined = userDefined; | |
} | |
@Override | |
public boolean isCollection() { | |
return result != null && result.isCollection(); | |
} | |
public boolean isSimpleXMLFormat() { | |
return result != null && result.getSimpleXMLFormat() != null; | |
} | |
public boolean isAttachment() { | |
return result != null && result.getAttachment() != null; | |
} | |
public QName getResultType() { | |
if (result != null) { | |
return result.getType(); | |
} | |
return null; | |
} | |
@Override | |
public boolean hasResponse() { | |
return result != null; | |
} | |
@Override | |
public void validate(XRServiceAdapter xrService) { | |
super.validate(xrService); | |
QName resultType = result == null ? null : result.getType(); | |
if (resultType != null) { | |
if (!resultType.getNamespaceURI().equals(SCHEMA_URL)) { | |
boolean sxf = resultType.getLocalPart().equals(DEFAULT_SIMPLE_XML_FORMAT_TAG) || | |
resultType.getLocalPart().equals(CURSOR_OF_STR + DEFAULT_SIMPLE_XML_FORMAT_TAG); | |
// check descriptor for Schema's high-level element type 'resultType' | |
if (!sxf && !xrService.descriptorsByQName.containsKey(resultType)) { | |
throw DBWSException.resultHasNoMapping(resultType.toString(), name); | |
} | |
} | |
} | |
if (queryHandler != null) { | |
queryHandler.validate(xrService, this); | |
} | |
} | |
public class DataHandlerInstantiationPolicy extends InstantiationPolicy { | |
protected String mimeType; | |
public DataHandlerInstantiationPolicy(String mimeType) { | |
super(); | |
this.mimeType = mimeType; | |
} | |
@Override | |
public Object buildNewInstance() throws DescriptorException { | |
return new DataHandler(null, mimeType); | |
} | |
} | |
@Override | |
public void initialize(XRServiceAdapter xrService) { | |
super.initialize(xrService); | |
if (queryHandler == null) { | |
// session query instead of named query | |
DatabaseQuery dq = xrService.getORSession().getQuery(name); | |
if (dq != null) { | |
queryHandler = new QueryHandler(){ | |
public void initializeDatabaseQuery(XRServiceAdapter xrService, QueryOperation queryOperation) { | |
// do nothing | |
} | |
public void initializeArguments(XRServiceAdapter xrService, | |
QueryOperation queryOperation, DatabaseQuery databaseQuery) { | |
// do nothing | |
} | |
public void initializeCall(XRServiceAdapter xrService, | |
QueryOperation queryOperation, DatabaseQuery databaseQuery) { | |
// do nothing | |
} | |
}; | |
queryHandler.setDatabaseQuery(dq); | |
} | |
} | |
if (queryHandler == null) { | |
throw DBWSException.couldNotLocateQueryForSession(name, | |
xrService.getORSession().getName()); | |
} | |
queryHandler.initialize(xrService, this); | |
Session oxSession = xrService.getOXSession(); | |
QName resultType = result == null ? null : result.getType(); | |
addSimpleXMLFormatModelDescriptor(xrService); | |
addValueObjectDescriptor(xrService); | |
if (resultType == null) { | |
if (isAttachment()) { | |
Attachment attachment = result.getAttachment(); | |
XMLDescriptor descriptor = | |
(XMLDescriptor)oxSession.getProject().getClassDescriptor(DataHandler.class); | |
if (descriptor == null) { | |
descriptor = new XMLDescriptor(); | |
descriptor.setAlias(DATAHANDLER_STR); | |
descriptor.setJavaClass(DataHandler.class); | |
descriptor.setInstantiationPolicy( | |
this.new DataHandlerInstantiationPolicy(attachment.getMimeType())); | |
XMLBinaryDataMapping mapping = new XMLBinaryDataMapping(); | |
mapping.setAttributeName(RESULTS_STR); | |
mapping.setAttributeAccessor(new AttributeAccessor() { | |
@Override | |
public Object getAttributeValueFromObject(Object object) | |
throws DescriptorException { | |
Object result = null; | |
InputStream is = null; | |
DataHandler dataHandler = (DataHandler)object; | |
try { | |
result = dataHandler.getContent(); | |
if (result instanceof InputStream) { | |
is = (InputStream)result; | |
byte[] buf = new byte[2048]; | |
ByteArrayOutputStream baos = new ByteArrayOutputStream(); | |
int bytesRead = is.read(buf); | |
while (bytesRead >= 0) { | |
baos.write(buf, 0, bytesRead); | |
bytesRead = is.read(buf); | |
} | |
result = baos.toByteArray(); | |
} | |
} catch (IOException e) { | |
// ignore | |
} finally { | |
try { | |
is.close(); | |
} catch (IOException e) { | |
} | |
} | |
return result; | |
} | |
@Override | |
public void setAttributeValueInObject(Object object, Object value) | |
throws DescriptorException { | |
} | |
}); | |
mapping.setXPath(DEFAULT_SIMPLE_XML_FORMAT_TAG + SLASH_CHAR + | |
DEFAULT_SIMPLE_XML_TAG + ATTACHMENT_STR); | |
mapping.setSwaRef(true); | |
mapping.setShouldInlineBinaryData(false); | |
mapping.setMimeType(attachment.getMimeType()); | |
descriptor.addMapping(mapping); | |
NamespaceResolver nr = new NamespaceResolver(); | |
descriptor.setNamespaceResolver(nr); | |
oxSession.getProject().addDescriptor(descriptor); | |
((DatabaseSessionImpl)oxSession) | |
.initializeDescriptorIfSessionAlive(descriptor); | |
xrService.getXMLContext().storeXMLDescriptorByQName(descriptor); | |
} | |
} | |
} | |
} | |
protected void addValueObjectDescriptor(XRServiceAdapter xrService) { | |
Session oxSession = xrService.getOXSession(); | |
XMLDescriptor descriptor = (XMLDescriptor)oxSession.getProject().getClassDescriptor( | |
ValueObject.class); | |
if (descriptor == null) { | |
descriptor = new XMLDescriptor(); | |
descriptor.setAlias(VALUEOBJECT_STR); | |
descriptor.setJavaClass(ValueObject.class); | |
XMLDirectMapping mapping = new XMLDirectMapping(); | |
mapping.setAttributeName(VALUE_STR); | |
mapping.setXPath(VALUE_STR); | |
descriptor.addMapping(mapping); | |
NamespaceResolver nr = new NamespaceResolver(); | |
descriptor.setNamespaceResolver(nr); | |
oxSession.getProject().addDescriptor(descriptor); | |
((DatabaseSessionImpl)oxSession) | |
.initializeDescriptorIfSessionAlive(descriptor); | |
xrService.getXMLContext().storeXMLDescriptorByQName(descriptor); | |
} | |
} | |
protected void addSimpleXMLFormatModelDescriptor(XRServiceAdapter xrService) { | |
if (isSimpleXMLFormat()) { | |
Session oxSession = xrService.getOXSession(); | |
XMLDescriptor simpleXMLFormatDescriptor = (XMLDescriptor)oxSession. | |
getProject().getClassDescriptor(SimpleXMLFormatModel.class); | |
if (simpleXMLFormatDescriptor == null) { | |
simpleXMLFormatDescriptor = new XMLDescriptor(); | |
simpleXMLFormatDescriptor.setJavaClass(SimpleXMLFormatModel.class); | |
simpleXMLFormatDescriptor.setAlias(DEFAULT_SIMPLE_XML_FORMAT_TAG); | |
simpleXMLFormatDescriptor.setDefaultRootElement(DEFAULT_SIMPLE_XML_FORMAT_TAG); | |
XMLFragmentCollectionMapping xmlTag = new XMLFragmentCollectionMapping(); | |
xmlTag.setAttributeName(SIMPLEXML_STR); | |
xmlTag.setXPath(DEFAULT_SIMPLE_XML_TAG); | |
simpleXMLFormatDescriptor.addMapping(xmlTag); | |
NamespaceResolver nr = new NamespaceResolver(); | |
simpleXMLFormatDescriptor.setNamespaceResolver(nr); | |
XMLSchemaURLReference schemaReference = new XMLSchemaURLReference(EMPTY_STR); | |
schemaReference.setSchemaContext(SIMPLEXML_FORMAT_STR); | |
schemaReference.setType(XMLSchemaReference.COMPLEX_TYPE); | |
simpleXMLFormatDescriptor.setSchemaReference(schemaReference); | |
oxSession.getProject().addDescriptor(simpleXMLFormatDescriptor); | |
((DatabaseSessionImpl)oxSession) | |
.initializeDescriptorIfSessionAlive(simpleXMLFormatDescriptor); | |
xrService.getXMLContext().storeXMLDescriptorByQName(simpleXMLFormatDescriptor); | |
} | |
} | |
} | |
/** | |
* Execute <tt>SELECT</tt> operation on the database | |
* @param xrService parent <code>XRService</code> that owns this <code>Operation</code> | |
* @param invocation contains runtime argument values to be bound to the list of | |
* {@link Parameter}'s. | |
* @return result - the result of the underlying <tt>SELECT</tt> operation on | |
* the database, or <code>null</code>. | |
* | |
* @see {@link Operation} | |
*/ | |
@Override | |
public Object invoke(XRServiceAdapter xrService, Invocation invocation) { | |
DatabaseQuery query = queryHandler.getDatabaseQuery(); | |
if (query.getProperty(DATABASEQUERY_STR) != null) { | |
query = (DatabaseQuery) query.getProperty(DATABASEQUERY_STR); | |
} | |
// a named query created via ORM metadata processing does not have | |
// parameters set, however, the operation should | |
if (query.getArguments().size() == 0) { | |
int idx = 0; | |
for (Parameter param : getParameters()) { | |
// for custom SQL query (as configured via ORM metadata | |
// processing) we add args by position | |
query.addArgument(Integer.toString(++idx), Util.SCHEMA_2_CLASS.get(param.getType())); | |
query.addArgumentValue(invocation.getParameter(param.getName())); | |
} | |
} else { | |
List<Object> argVals = new ArrayList<Object>(); | |
// need to set argument values | |
for (Parameter param : getParameters()) { | |
argVals.add(invocation.getParameter(param.getName())); | |
} | |
query.setArgumentValues(argVals); | |
} | |
// for SimpleXML + DataReadQuery we need to set MAP result type | |
if (isSimpleXMLFormat() && query.isDataReadQuery()) { | |
((DataReadQuery) query).setResultType(DataReadQuery.MAP); | |
} | |
// now execute the query | |
Object value = xrService.getORSession().getActiveSession().executeQuery(query); | |
if (value != null) { | |
// a recent change in core results in an empty vector being returned in cases | |
// where before we'd expect an int value (typically 1) - need to handle this | |
if (result != null && (result.getType() == INT_QNAME || result.getType().equals(SXF_QNAME))) { | |
if (value instanceof ArrayList && ((ArrayList) value).isEmpty()) { | |
((ArrayList) value).add(1); | |
} else if (value instanceof Vector && ((Vector) value).isEmpty()) { | |
((Vector) value).add(1); | |
} | |
} | |
// JPA spec returns an ArrayList<Object[]> for stored procedure queries - will need to unwrap. | |
// Note that for legacy deployment XML projects this is not the case. | |
if (value instanceof ArrayList) { | |
ArrayList returnedList = (ArrayList) value; | |
if (returnedList.size() > 0 && returnedList.get(0) instanceof Object[]) { | |
Object[] objs = (Object[]) returnedList.get(0); | |
if (isCollection()) { | |
value = new ArrayList(); | |
for (Object obj : objs) { | |
((ArrayList) value).add(obj); | |
} | |
} else { | |
value = objs[0]; | |
} | |
} | |
} | |
// handle SimpleXML | |
if (isSimpleXMLFormat()) { | |
value = createSimpleXMLFormat(xrService, value); | |
} else { | |
if (!isCollection() && value instanceof Vector) { | |
// JPAQuery will return a single result in a Vector | |
if (((Vector) value).isEmpty()) { | |
return null; | |
} | |
value = ((Vector) value).firstElement(); | |
} | |
QName resultType = getResultType(); | |
if (resultType != null) { | |
// handle binary content | |
if (isAttachment() || (!isCollection() && resultType.equals(BASE_64_BINARY_QNAME))) { | |
String mimeType = DEFAULT_ATTACHMENT_MIMETYPE; | |
if (isAttachment() && result.getAttachment().getMimeType() != null) { | |
mimeType = result.getAttachment().getMimeType(); | |
} | |
// handle BLOB types | |
if (value instanceof Blob) { | |
value = ((XMLConversionManager) xrService.getOXSession(). | |
getDatasourcePlatform().getConversionManager()). | |
convertObject((Blob) value, ClassConstants.APBYTE); | |
} | |
return AttachmentHelper.buildAttachmentHandler((byte[])value, mimeType); | |
} | |
if (resultType.getNamespaceURI().equals(SCHEMA_URL)) { | |
// handle primitive types | |
ValueObject vo = new ValueObject(); | |
vo.value = value; | |
value = vo; | |
} else { | |
Object targetObject = value; | |
if (xrService.descriptorsByQName.containsKey(resultType)) { | |
XMLDescriptor xdesc = xrService.descriptorsByQName.get(resultType); | |
ClassDescriptor desc = xrService.getORSession().getDescriptorForAlias(xdesc.getAlias()); | |
if (desc.isAggregateDescriptor() && !desc.isObjectRelationalDataTypeDescriptor() && !desc.isRelationalDescriptor()) { | |
if (isCollection()) { | |
XRDynamicEntity_CollectionWrapper xrCollWrapper = new XRDynamicEntity_CollectionWrapper(); | |
Vector<AbstractRecord> results = (Vector<AbstractRecord>)value; | |
for (int i = 0, len = results.size(); i < len; i++) { | |
Object o = desc.getObjectBuilder().buildNewInstance(); | |
populateTargetObjectFromRecord(desc.getMappings(), results.get(i), o, (AbstractSession)xrService.getORSession()); | |
xrCollWrapper.add(o); | |
} | |
targetObject = xrCollWrapper; | |
} else { | |
targetObject = desc.getObjectBuilder().buildNewInstance(); | |
populateTargetObjectFromRecord(desc.getMappings(), (AbstractRecord) value, targetObject, (AbstractSession)xrService.getORSession()); | |
} | |
} else if (isCollection() && value instanceof Vector) { | |
// could be a collection of populated objects, in which case we just return it | |
if (((Vector) value).size() > 0 && !(((Vector) value).get(0) instanceof AbstractRecord)) { | |
return value; | |
} | |
XRDynamicEntity_CollectionWrapper xrCollWrapper = new XRDynamicEntity_CollectionWrapper(); | |
Vector<AbstractRecord> results = (Vector<AbstractRecord>)value; | |
for (int i = 0, len = results.size(); i < len; i++) { | |
Object o = desc.getObjectBuilder().buildNewInstance(); | |
populateTargetObjectFromRecord(desc.getMappings(), results.get(i), o, (AbstractSession)xrService.getORSession()); | |
xrCollWrapper.add(o); | |
} | |
targetObject = xrCollWrapper; | |
} else if (value instanceof AbstractRecord) { | |
targetObject = desc.getObjectBuilder().buildNewInstance(); | |
populateTargetObjectFromRecord(desc.getMappings(), (AbstractRecord) value, targetObject, (AbstractSession)xrService.getORSession()); | |
} | |
} | |
if (value instanceof ArrayList) { | |
XMLDescriptor xdesc = xrService.descriptorsByQName.get(resultType); | |
ClassDescriptor desc = xrService.getORSession().getDescriptorForAlias(xdesc.getAlias()); | |
targetObject = desc.getObjectBuilder().buildNewInstance(); | |
Object[] objs = new Object[1]; | |
objs[0] = ((ArrayList)value).get(0); | |
DatabaseRecord dr = new DatabaseRecord(); | |
dr.add(new DatabaseField(ITEMS_STR), objs); | |
populateTargetObjectFromRecord(desc.getMappings(), (AbstractRecord) dr, targetObject, (AbstractSession)xrService.getORSession()); | |
} | |
value = targetObject; | |
} | |
} | |
} | |
} | |
return value; | |
} | |
protected void populateTargetObjectFromRecord(Vector<DatabaseMapping> mappings, | |
AbstractRecord record, Object targetObject, AbstractSession session) { | |
ReadObjectQuery roq = new ReadObjectQuery(); | |
roq.setSession(session); | |
for (DatabaseMapping dm : mappings) { | |
dm.readFromRowIntoObject(record, null, targetObject, null, roq, session, true); | |
} | |
} | |
public Object createSimpleXMLFormat(XRServiceAdapter xrService, Object value) { | |
XMLRoot xmlRoot = new XMLRoot(); | |
SimpleXMLFormat simpleXMLFormat = result.getSimpleXMLFormat(); | |
String tempSimpleXMLFormatTag = SimpleXMLFormat.DEFAULT_SIMPLE_XML_FORMAT_TAG; | |
String simpleXMLFormatTag = simpleXMLFormat.getSimpleXMLFormatTag(); | |
if (simpleXMLFormatTag != null && !EMPTY_STR.equals(simpleXMLFormatTag)) { | |
tempSimpleXMLFormatTag = simpleXMLFormatTag; | |
} | |
xmlRoot.setLocalName(tempSimpleXMLFormatTag); | |
String tempXMLTag = DEFAULT_SIMPLE_XML_TAG; | |
String xmlTag = simpleXMLFormat.getXMLTag(); | |
if (xmlTag != null && !EMPTY_STR.equals(xmlTag)) { | |
tempXMLTag = xmlTag; | |
} | |
Vector<DatabaseRecord> records = null; | |
if (value instanceof ArrayList) { | |
// JPA query results in a list of raw values | |
// Here we have raw values returned as opposed to DatabaseRecords - this means | |
// we need to figure out the tag names based on the call's output parameters. | |
// assumes JPAQuery | |
JPAQuery jpaQuery = (JPAQuery) queryHandler.getDatabaseQuery(); | |
// to match field names with results, we need to gather the database fields from each of the Output parameters | |
List<DatabaseField> paramFlds = new ArrayList<DatabaseField>(); | |
DatasourceCall dsCall = (DatasourceCall) jpaQuery.getDatabaseQuery().getDatasourceCall(); | |
for (Object obj : dsCall.getParameters()) { | |
if (obj instanceof OutputParameterForCallableStatement) { | |
paramFlds.add(((OutputParameterForCallableStatement) obj).getOutputField()); | |
} else if (obj instanceof Object[]) { | |
Object[] objArray = (Object[]) obj; | |
for (int i = 0; i < objArray.length; i++) { | |
Object o = objArray[i]; | |
if (o instanceof OutputParameterForCallableStatement) { | |
paramFlds.add(((OutputParameterForCallableStatement) o).getOutputField()); | |
} | |
} | |
} | |
} | |
// now create a record using DatabaseField/value pairs | |
DatabaseRecord dr = new DatabaseRecord(); | |
if (paramFlds.size() > 0) { | |
for (int i=0; i < ((ArrayList) value).size(); i++) { | |
dr.add(paramFlds.get(i), ((ArrayList) value).get(i)); | |
} | |
} else { | |
dr.add(new DatabaseField(RESULT_STR), ((ArrayList) value).get(0)); | |
} | |
records = new Vector<DatabaseRecord>(); | |
records.add(dr); | |
} else if (value instanceof Vector) { | |
Class vectorContent = ((Vector)value).firstElement().getClass(); | |
if (DatabaseRecord.class.isAssignableFrom(vectorContent)) { | |
records = (Vector<DatabaseRecord>)value; | |
} else { | |
records = new Vector<DatabaseRecord>(); | |
DatabaseRecord dr = new DatabaseRecord(); | |
dr.add(new DatabaseField(RESULT_STR), ((Vector)value).firstElement()); | |
records.add(dr); | |
} | |
} else { | |
records = new Vector<DatabaseRecord>(); | |
DatabaseRecord dr = new DatabaseRecord(); | |
dr.add(new DatabaseField(RESULT_STR), value); | |
records.add(dr); | |
} | |
SimpleXMLFormatModel simpleXMLFormatModel = new SimpleXMLFormatModel(); | |
XMLConversionManager conversionManager = | |
(XMLConversionManager) xrService.getOXSession().getDatasourcePlatform().getConversionManager(); | |
for (DatabaseRecord dr : records) { | |
Element rowElement = TEMP_DOC.createElement(tempXMLTag); | |
for (DatabaseField field : (Vector<DatabaseField>)dr.getFields()) { | |
// handle complex types, i.e. ones we have a descriptor for | |
if (field instanceof ObjectRelationalDatabaseField) { | |
ObjectRelationalDatabaseField ordtField = (ObjectRelationalDatabaseField) field; | |
if (xrService.getOXSession().getDescriptor(ordtField.getType()) != null) { | |
xrService.getXMLContext().createMarshaller().marshal(dr.get(field), rowElement); | |
continue; | |
} | |
} | |
Object fieldValue = dr.get(field); | |
if (fieldValue != null) { | |
if (fieldValue instanceof Calendar) { | |
Calendar cValue = (Calendar)fieldValue; | |
fieldValue = conversionManager.convertObject(cValue, STRING, DATE_TIME_QNAME); | |
} | |
if (fieldValue instanceof Date) { | |
Date dValue = (Date)fieldValue; | |
fieldValue = conversionManager.convertObject(dValue, STRING, DATE_QNAME); | |
} else if (fieldValue instanceof Time) { | |
Time tValue = (Time)fieldValue; | |
fieldValue = conversionManager.convertObject(tValue, STRING, TIME_QNAME); | |
} else if (fieldValue instanceof Timestamp) { | |
Timestamp tsValue = (Timestamp)fieldValue; | |
fieldValue = conversionManager.convertObject(tsValue, STRING, DATE_TIME_QNAME); | |
} else if (fieldValue instanceof Blob) { | |
fieldValue = conversionManager.convertObject((Blob) fieldValue, ClassConstants.APBYTE); | |
} else if (fieldValue.getClass().getName().equalsIgnoreCase(ORACLESQLXML_STR)) { | |
// handle XMLType case where an oracle.jdbc.driver.OracleSQLXML instance was returned | |
try { | |
Class oracleSQLXML; | |
Method getStringMethod; | |
if (PrivilegedAccessHelper.shouldUsePrivilegedAccess()) { | |
oracleSQLXML = AccessController.doPrivileged(new PrivilegedClassForName(ORACLESQLXML_STR, true, this.getClass().getClassLoader())); | |
getStringMethod = AccessController.doPrivileged(new PrivilegedGetDeclaredMethod(oracleSQLXML, GETSTRING_METHOD, new Class[] {})); | |
fieldValue = (String) AccessController.doPrivileged(new PrivilegedMethodInvoker(getStringMethod, fieldValue, new Object[] {})); | |
} else { | |
oracleSQLXML = PrivilegedAccessHelper.getClassForName(ORACLESQLXML_STR, true, this.getClass().getClassLoader()); | |
getStringMethod = PrivilegedAccessHelper.getDeclaredMethod(oracleSQLXML, GETSTRING_METHOD, new Class[] {}); | |
fieldValue = (String) PrivilegedAccessHelper.invokeMethod(getStringMethod, fieldValue, new Object[] {}); | |
} | |
} catch (Exception x) { | |
// if the required resources are not available there's nothing we can do... | |
} | |
} else if (fieldValue.getClass().getName().equalsIgnoreCase(ORACLEOPAQUE_STR)) { | |
// handle XMLType case where an oracle.sql.OPAQUE instance was returned | |
try { | |
Class oracleOPAQUE; | |
Class xmlTypeFactoryClass; | |
Constructor xmlTypeFactoryConstructor; | |
Object xmlTypeFactory; | |
Method getStringMethod; | |
if (PrivilegedAccessHelper.shouldUsePrivilegedAccess()) { | |
oracleOPAQUE = AccessController.doPrivileged(new PrivilegedClassForName(ORACLEOPAQUE_STR, true, this.getClass().getClassLoader())); | |
xmlTypeFactoryClass = AccessController.doPrivileged(new PrivilegedClassForName(XMLTYPEFACTORY_STR, true, this.getClass().getClassLoader())); | |
xmlTypeFactoryConstructor = AccessController.doPrivileged(new PrivilegedGetConstructorFor(xmlTypeFactoryClass, new Class[0], true)); | |
xmlTypeFactory = AccessController.doPrivileged(new PrivilegedInvokeConstructor(xmlTypeFactoryConstructor, new Object[0])); | |
getStringMethod = AccessController.doPrivileged(new PrivilegedGetDeclaredMethod(xmlTypeFactoryClass, GETSTRING_METHOD, new Class[] {oracleOPAQUE})); | |
fieldValue = (String) AccessController.doPrivileged(new PrivilegedMethodInvoker(getStringMethod, fieldValue, new Object[] {})); | |
} else { | |
oracleOPAQUE = PrivilegedAccessHelper.getClassForName(ORACLEOPAQUE_STR, false, this.getClass().getClassLoader()); | |
xmlTypeFactoryClass = PrivilegedAccessHelper.getClassForName(XMLTYPEFACTORY_STR, true, this.getClass().getClassLoader()); | |
xmlTypeFactoryConstructor = PrivilegedAccessHelper.getConstructorFor(xmlTypeFactoryClass, new Class[0], true); | |
xmlTypeFactory = PrivilegedAccessHelper.invokeConstructor(xmlTypeFactoryConstructor, new Object[0]); | |
getStringMethod = PrivilegedAccessHelper.getDeclaredMethod(xmlTypeFactoryClass, GETSTRING_METHOD, new Class[] {oracleOPAQUE}); | |
fieldValue = (String) PrivilegedAccessHelper.invokeMethod(getStringMethod, xmlTypeFactory, new Object[] {fieldValue}); | |
} | |
} catch (Exception x) { | |
// if the required resources are not available there's nothing we can do... | |
} | |
} | |
String elementName; | |
if (field.getName() == null || (elementName = sqlToXmlName(field.getName())).equals(EMPTY_STR)) { | |
// return arg from stored function has no name | |
elementName = RESULT_STR; | |
} | |
Element columnElement = TEMP_DOC.createElement(elementName); | |
rowElement.appendChild(columnElement); | |
String fieldValueString = fieldValue.toString(); | |
// handle binary content - attachments dealt with in invoke() above | |
if (result.getType().equals(BASE_64_BINARY_QNAME)) { | |
fieldValueString = Helper.buildHexStringFromBytes(Base64.base64Encode((byte[])fieldValue)); | |
columnElement.setAttributeNS(XMLNS_URL, XSD_STR, SCHEMA_URL); | |
columnElement.setAttributeNS(XMLNS_URL, XSI_STR, SCHEMA_INSTANCE_URL); | |
columnElement.setAttributeNS(SCHEMA_INSTANCE_URL, XSITYPE_STR, BASE64_BINARY_STR); | |
} | |
columnElement.appendChild(TEMP_DOC.createTextNode(fieldValueString)); | |
} | |
} | |
simpleXMLFormatModel.simpleXML.add(rowElement); | |
} | |
xmlRoot.setObject(simpleXMLFormatModel); | |
return xmlRoot; | |
} | |
} |