blob: 07141090e4ba808c8ced7abc1f7db996ddb8570c [file] [log] [blame]
/*
* Copyright (c) 1998, 2021 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.testing.oxm;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.StringReader;
import java.io.StringWriter;
import java.io.Writer;
import java.lang.reflect.Constructor;
import java.util.Collection;
import java.util.Iterator;
import java.util.TimeZone;
import jakarta.xml.bind.JAXBElement;
import javax.xml.stream.XMLEventReader;
import javax.xml.stream.XMLEventWriter;
import javax.xml.stream.XMLInputFactory;
import javax.xml.stream.XMLOutputFactory;
import javax.xml.stream.XMLStreamReader;
import javax.xml.stream.XMLStreamWriter;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import org.eclipse.persistence.descriptors.ClassDescriptor;
import org.eclipse.persistence.exceptions.ValidationException;
import org.eclipse.persistence.internal.helper.ConversionManager;
import org.eclipse.persistence.oxm.XMLContext;
import org.eclipse.persistence.oxm.XMLLogin;
import org.eclipse.persistence.oxm.XMLMarshaller;
import org.eclipse.persistence.oxm.platform.DOMPlatform;
import org.eclipse.persistence.oxm.platform.SAXPlatform;
import org.eclipse.persistence.sessions.Project;
import org.eclipse.persistence.sessions.Session;
import org.eclipse.persistence.internal.security.PrivilegedAccessHelper;
import org.eclipse.persistence.internal.sessions.factories.MissingDescriptorListener;
import org.eclipse.persistence.internal.sessions.factories.ObjectPersistenceRuntimeXMLProject_11_1_1;
import org.eclipse.persistence.sessions.factories.SessionManager;
import org.eclipse.persistence.sessions.factories.XMLProjectReader;
import org.eclipse.persistence.sessions.factories.XMLProjectWriter;
import org.w3c.dom.Document;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
public abstract class OXTestCase extends XMLTestCase {
protected static XMLInputFactory XML_INPUT_FACTORY;
protected static XMLOutputFactory XML_OUTPUT_FACTORY;
protected static Class staxResultClass;
protected static String staxResultClassName = "javax.xml.transform.stax.StAXResult";
protected static Class staxSourceClass;
protected static String staxSourceClassName = "javax.xml.transform.stax.StAXSource";
protected static Constructor staxResultStreamWriterConstructor;
protected static Constructor staxResultEventWriterConstructor;
protected static Constructor staxSourceStreamReaderConstructor;
protected static Constructor staxSourceEventReaderConstructor;
protected static final String TIMEZONE_OFFSET;
static {
try {
XML_INPUT_FACTORY = XMLInputFactory.newInstance();
XML_OUTPUT_FACTORY = XMLOutputFactory.newInstance();
} catch(javax.xml.stream.FactoryConfigurationError error){
XML_INPUT_FACTORY = null;
XML_OUTPUT_FACTORY = null;
}
try {
staxResultClass = PrivilegedAccessHelper.getClassForName(staxResultClassName);
staxResultStreamWriterConstructor = PrivilegedAccessHelper.getConstructorFor(staxResultClass, new Class[]{XMLStreamWriter.class}, true);
staxResultEventWriterConstructor = PrivilegedAccessHelper.getConstructorFor(staxResultClass, new Class[]{XMLEventWriter.class}, true);
} catch(Exception ex) {
staxResultClass = null;
}
try {
staxSourceClass = PrivilegedAccessHelper.getClassForName(staxSourceClassName);
staxSourceStreamReaderConstructor = PrivilegedAccessHelper.getConstructorFor(staxSourceClass, new Class[]{XMLStreamReader.class}, true);
staxSourceEventReaderConstructor = PrivilegedAccessHelper.getConstructorFor(staxSourceClass, new Class[]{XMLEventReader.class}, true);
} catch(Exception ex) {
staxSourceClass = null;
}
// Bug #454154 and #453330
// DateAndTime tests are susceptible to changes in time zone. And since they were not written to support
// GMT+00:00 time zone, which in Java translates to "Z" short-hand,
// and since further complications arise from the fact that TIME_OFFSET is computed only once per OXTestCase
// class and without having any information about daylight savings offset,
// some tests were failing under GMT+00:00 Time Zone.
// There are 2 options for how to solve this problem now: do massive rewrite of all DateAndTime tests or use a
// time zone that does not cause problems. Second option has been chosen for now.
TimeZone.setDefault(TimeZone.getTimeZone("America/Los_Angeles"));
int offsetInMillis = TimeZone.getDefault().getRawOffset();
String offset = String.format("%02d:%02d", Math.abs(offsetInMillis / 3600000), Math.abs((offsetInMillis / 60000) % 60));
TIMEZONE_OFFSET = offsetInMillis == 0 ? "Z" : ((offsetInMillis >= 0 ? "+" : "-") + offset);
}
public boolean useLogging = false;
public static enum Platform { DOM, SAX, DOC_PRES };
public static enum Metadata { JAVA, XML_TOPLINK, XML_ECLIPSELINK };
public static Platform platform;;
public static Metadata metadata;
// Constants
public static final String PLATFORM_KEY = "platformType";
public static final String PLATFORM_DOM = "DOM";
public static final String PLATFORM_DOC_PRES = "DOC_PRES";
public static final String PLATFORM_SAX = "SAX";
public static final String METADATA_KEY = "metadataType";
public static final String METADATA_JAVA = "JAVA";
public static final String METADATA_TOPLINK = "XML_TOPLINK";
public static final String METADATA_XML_ECLIPSELINK = "XML_ECLIPSELINK";
public OXTestCase(String name) {
super(name);
useLogging = Boolean.getBoolean("useLogging");
platform = getPlatform();
metadata = getMetadata();
}
public XMLContext getXMLContext(String name) {
Session session = SessionManager.getManager().getSession(name, false);
Project project = session.getProject();
return getXMLContext(project);
}
public XMLContext getXMLContext(Project project) {
if (platform == Platform.DOC_PRES) {
Collection<ClassDescriptor> descriptors = project.getDescriptors().values();
Iterator<ClassDescriptor> iter = descriptors.iterator();
while (iter.hasNext()) {
ClassDescriptor nextDesc = iter.next();
if (nextDesc instanceof org.eclipse.persistence.oxm.XMLDescriptor) {
((org.eclipse.persistence.oxm.XMLDescriptor)nextDesc).setShouldPreserveDocument(true);
}
}
}
Project newProject = this.getNewProject(project, null);
return new XMLContext(newProject);
}
public XMLContext getXMLContext(Project project, ClassLoader classLoader) {
ConversionManager.getDefaultManager().setLoader(classLoader);
Project newProject = this.getNewProject(project, classLoader);
newProject.getDatasourceLogin().getDatasourcePlatform().getConversionManager().setLoader(classLoader);
return new XMLContext(newProject);
}
public Project getNewProject(Project originalProject) {
return getNewProject(originalProject, null);
}
public Project getNewProject(Project originalProject, ClassLoader classLoader) {
Project newProject = originalProject;
switch (metadata) {
case JAVA:
break;
default:
try {
// Write the deployment XML file to deploymentXML-file.xml
String fileName = "deploymentXML-file.xml";
FileWriter fWriter = new FileWriter(fileName);
write(originalProject, fWriter);
fWriter.close();
// Also write the deployment XML file to a stringwriter for logging
if (useLogging) {
StringWriter stringWriter = new StringWriter();
write(originalProject, stringWriter);
log("DEPLOYMENT XML " + stringWriter.toString());
}
// Read the deploymentXML-file.xml back in with XMLProjectReader
FileInputStream inStream = new FileInputStream(fileName);
FileReader fileReader = new FileReader(fileName);
newProject = XMLProjectReader.read(fileReader, classLoader);
inStream.close();
fileReader.close();
File f = new File(fileName);
f.delete();
} catch (Exception e) {
e.printStackTrace();
StringWriter stringWriter = new StringWriter();
write(originalProject, stringWriter);
StringReader reader = new StringReader(stringWriter.toString());
log("DEPLOYMENT XML" + stringWriter.toString());
newProject = XMLProjectReader.read(reader, classLoader);
}
}
if ((newProject.getDatasourceLogin() == null) || (!(newProject.getDatasourceLogin() instanceof XMLLogin))) {
newProject.setDatasourceLogin(new XMLLogin());
}
switch (platform) {
case SAX:
newProject.getDatasourceLogin().setPlatform(new SAXPlatform());
break;
default:
newProject.getDatasourceLogin().setPlatform(new DOMPlatform());
}
return newProject;
}
protected void log(Document document) {
if (!useLogging) {
return;
}
try {
TransformerFactory transformerFactory = TransformerFactory.newInstance();
Transformer transformer = transformerFactory.newTransformer();
DOMSource source = new DOMSource(document);
StreamResult result = new StreamResult(System.out);
transformer.transform(source, result);
} catch (Exception e) {
e.printStackTrace();
}
}
protected void log(String string) {
if (useLogging) {
System.out.println(string);
}
}
protected void log(byte[] bytes) {
if (useLogging) {
for (int i = 0; i < bytes.length; i++) {
System.out.print(bytes[i]);
}
}
}
@Override
public String getName() {
String longClassName = this.getClass().getName();
String shortClassName = longClassName.substring(longClassName.lastIndexOf(".") + 1, longClassName.length() - 1);
String description = "";
switch (metadata) {
case XML_ECLIPSELINK:
description = "Deployment XML w/";
break;
case XML_TOPLINK:
description = "TL Deployment XML w/";
break;
default:
description = "Java Project Source w/";
}
switch (platform) {
case DOC_PRES:
description += "Doc Pres: ";
break;
case DOM:
description += "DOM Parsing: ";
break;
default:
description += "SAX Parsing: ";
}
return description + shortClassName + ": " + super.getName();
}
public static void removeEmptyTextNodes(Node node) {
NodeList nodeList = node.getChildNodes();
Node childNode;
for (int x = nodeList.getLength() - 1; x >= 0; x--) {
childNode = nodeList.item(x);
if (childNode.getNodeType() == Node.TEXT_NODE) {
if (childNode.getNodeValue().trim().equals("")) {
node.removeChild(childNode);
}
} else if (childNode.getNodeType() == Node.ELEMENT_NODE) {
removeEmptyTextNodes(childNode);
}
}
}
public static void removeCopyrightNode(Node node) {
NodeList nodeList = node.getChildNodes();
Node childNode;
for (int x = 0; x < nodeList.getLength(); x++) {
childNode = nodeList.item(x);
if (childNode.getNodeType() == Node.COMMENT_NODE) {
if (childNode.getNodeValue().trim().contains("Copyright")) {
node.removeChild(childNode);
break;
}
}
}
}
public static String removeWhiteSpaceFromString(String s) {
String returnString = s.replaceAll(" ", "");
returnString = returnString.replaceAll("\n", "");
returnString = returnString.replaceAll("\t", "");
returnString = returnString.replaceAll("\r", "");
return returnString;
}
public static String removeCopyrightFromString(String s) {
return s.replaceAll("<!--.*Copyright.*?-->", "");
}
/**
* Return the Platform to be used based on the "platformType"
* System property
*
* @see Platform
*/
public Platform getPlatform() {
String platformStr = System.getProperty(PLATFORM_KEY, PLATFORM_SAX);
if (platformStr.equals(PLATFORM_SAX)) {
return Platform.SAX;
}
if (platformStr.equals(PLATFORM_DOM)) {
return Platform.DOM;
}
return Platform.DOC_PRES;
}
/**
* Return the Metadata type based on the "metadataType"
* System property
*
* @see Metadata
*/
public Metadata getMetadata() {
String metadataStr = System.getProperty(METADATA_KEY, METADATA_JAVA);
if (metadataStr.equals(METADATA_JAVA)) {
return Metadata.JAVA;
}
if (metadataStr.equals(METADATA_XML_ECLIPSELINK)) {
return Metadata.XML_ECLIPSELINK;
}
return Metadata.XML_TOPLINK;
}
// Write out deployment XML
public void write(Project project, Writer writer) {
// Write out EclipseLink deployment XML
if (metadata == Metadata.XML_ECLIPSELINK) {
XMLProjectWriter.write(project, writer);
return;
}
// Write out TL deployment XML
XMLContext context = new XMLContext(new ObjectPersistenceRuntimeXMLProject_11_1_1());
context.getSession(project).getEventManager().addListener(new MissingDescriptorListener());
XMLMarshaller marshaller = context.createMarshaller();
marshaller.marshal(project, writer);
try {
writer.flush();
} catch (IOException exception) {
throw ValidationException.fileError(exception);
}
}
public void compareJAXBElementObjects(JAXBElement controlObj, JAXBElement testObj) {
compareJAXBElementObjects(controlObj, testObj, true);
}
public void compareJAXBElementObjects(JAXBElement controlObj, JAXBElement testObj, boolean namespaceAware) {
assertEquals(controlObj.getName().getLocalPart(), testObj.getName().getLocalPart());
if(namespaceAware){
assertEquals(controlObj.getName().getNamespaceURI(), testObj.getName().getNamespaceURI());
}
assertEquals(controlObj.getDeclaredType(), testObj.getDeclaredType());
Object controlValue = controlObj.getValue();
Object testValue = testObj.getValue();
if(controlValue == null) {
if(testValue == null){
return;
}
fail("Test value should have been null");
}else{
if(testValue == null){
fail("Test value should not have been null");
}
}
if(controlValue.getClass().isArray()){
compareArrays(controlValue, testValue);
}
else if (controlValue instanceof Collection){
Collection controlCollection = (Collection)controlValue;
Collection testCollection = (Collection)testValue;
Iterator<Object> controlIter = controlCollection.iterator();
Iterator<Object> testIter = testCollection.iterator();
assertEquals(controlCollection.getClass(), testCollection.getClass());
assertEquals(controlCollection.size(), testCollection.size());
while(controlIter.hasNext()){
Object nextControl = controlIter.next();
Object nextTest = testIter.next();
compareValues(nextControl, nextTest);
}
}else{
compareValues(controlValue, testValue);
}
}
@Override
protected void compareValues(Object controlValue, Object testValue){
if(controlValue instanceof JAXBElement && testValue instanceof JAXBElement){
compareJAXBElementObjects((JAXBElement)controlValue, (JAXBElement)testValue);
}else{
super.compareValues(controlValue, testValue);
}
}
protected String loadFileToString(String fileName){
InputStream inputStream = Thread.currentThread().getContextClassLoader().getResourceAsStream(fileName);
return loadInputStreamToString(inputStream);
}
protected String loadInputStreamToString(InputStream inputStream){
StringBuilder sb = new StringBuilder();
String lineSep = System.getProperty("line.separator");
try {
InputStreamReader inputStreamReader = new InputStreamReader(inputStream);
BufferedReader bufferedReader = new BufferedReader(inputStreamReader);
String str;
//Don't add the lineSep the first time
if(bufferedReader.ready()){
sb.append(bufferedReader.readLine());
}
while (bufferedReader.ready()) {
sb.append(lineSep);
sb.append(bufferedReader.readLine());
}
bufferedReader.close();
inputStreamReader.close();
inputStream.close();
} catch (IOException e) {
e.printStackTrace();
fail();
}
return sb.toString();
}
}