org.eclipse.persistence.internal.xr.QueryOperation Maven / Gradle / Ivy
Show all versions of eclipselink Show documentation
/*
* Copyright (c) 1998, 2024 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 v. 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0,
* or the Eclipse Distribution License v. 1.0 which is available at
* http://www.eclipse.org/org/documents/edl-v10.php.
*
* SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause
*/
// Contributors:
// Oracle - initial API and implementation from Oracle TopLink
package org.eclipse.persistence.internal.xr;
// Javase imports
import static org.eclipse.persistence.internal.helper.ClassConstants.STRING;
import static org.eclipse.persistence.internal.oxm.Constants.BASE_64_BINARY_QNAME;
import static org.eclipse.persistence.internal.oxm.Constants.DATE_QNAME;
import static org.eclipse.persistence.internal.oxm.Constants.DATE_TIME_QNAME;
import static org.eclipse.persistence.internal.oxm.Constants.INT_QNAME;
import static org.eclipse.persistence.internal.oxm.Constants.TIME_QNAME;
import static org.eclipse.persistence.internal.xr.Util.DEFAULT_ATTACHMENT_MIMETYPE;
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.internal.xr.Util.sqlToXmlName;
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.oxm.XMLConstants.SCHEMA_INSTANCE_URL;
import static org.eclipse.persistence.oxm.XMLConstants.SCHEMA_URL;
import static org.eclipse.persistence.oxm.XMLConstants.XMLNS_URL;
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.security.PrivilegedActionException;
import java.sql.Blob;
import java.sql.Date;
import java.sql.SQLException;
import java.sql.SQLXML;
import java.sql.Time;
import java.sql.Timestamp;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.List;
import java.util.Vector;
// Java extension imports
import jakarta.activation.DataHandler;
import javax.xml.namespace.QName;
// EclipseLink imports
import org.eclipse.persistence.descriptors.ClassDescriptor;
import org.eclipse.persistence.exceptions.DBWSException;
import org.eclipse.persistence.exceptions.DescriptorException;
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.logging.SessionLog;
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 org.w3c.dom.Element;
/**
* INTERNAL:An XR QueryOperation is an executable representation of a SELECT
* operation on the database.
*
* @author Mike Norman - [email protected]
* @since EclipseLink 1.x
*/
public class QueryOperation extends Operation {
public static final String ORACLEOPAQUE_STR = "oracle.sql.OPAQUE";
private static final String IORACLEOPAQUE_STR = "oracle.jdbc.OracleOpaque";
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);
}
}
// Made static final for performance reasons.
private static final class DataHandlerInstantiationPolicy extends InstantiationPolicy {
private final 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(){
@Override
public void initializeDatabaseQuery(XRServiceAdapter xrService, QueryOperation queryOperation) {
// do nothing
}
@Override
public void initializeArguments(XRServiceAdapter xrService,
QueryOperation queryOperation, DatabaseQuery databaseQuery) {
// do nothing
}
@Override
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(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;
DataHandler dataHandler = (DataHandler)object;
try {
result = dataHandler.getContent();
if (result instanceof InputStream) {
try (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
}
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 SELECT
operation on the database
* @param xrService parent XRService
that owns this Operation
* @param invocation contains runtime argument values to be bound to the list of
* {@link Parameter}'s.
* @return result - the result of the underlying SELECT
operation on
* the database, or null
.
*
* @see Operation
*/
@Override
@SuppressWarnings({"unchecked"})
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
List