blob: 3a1e5aa5380d238f2c2637059b26847a3ee6f3f9 [file] [log] [blame]
/*
* Copyright (c) 1998, 2020 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.sdo.helper;
import java.util.ArrayList;
import java.util.List;
import javax.xml.transform.Source;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.sax.SAXSource;
import javax.xml.transform.stream.StreamSource;
import org.eclipse.persistence.exceptions.SDOException;
import org.xml.sax.InputSource;
/**
* <p><b>Purpose</b>: Allow the contained schema resolver to resolve a schema based on a given namespace and schema location, and
* return either the resolved schema source or null, depending on whether the schema had been processed previously.
* <p><b>Responsibilities</b>:<ul>
* <li> Allow the contained schema resolver to return the referenced Schema given the source schema and namespace and
* schemaLocation values from an import or include
* <li> Keep track of previously processed schemas to avoid multiple processing and infinite looping
* </ul>
*
* @see org.eclipse.persistence.sdo.helper.SchemaResolver
* @see org.eclipse.persistence.sdo.helper.DefaultSchemaResolver
*/
public class SchemaResolverWrapper {
private SchemaResolver schemaResolver;
private List<String> systemIdList;
/**
* This constructor sets schemaResolver to the given value.
*
* @param resolver the SchemaResolver implementation that will be used to resolve
* imports/includes from a give source schema.
*/
public SchemaResolverWrapper(SchemaResolver resolver) {
schemaResolver = resolver;
systemIdList = new ArrayList<String>();
}
/**
* Resolve the Source if only a system ID is specified.
*/
public Source resolveSchema(Source sourceXSD) {
Source resolvedSchemaSource = null;
if(sourceXSD instanceof StreamSource) {
StreamSource streamSource = (StreamSource) sourceXSD;
if(null == streamSource.getInputStream() && null == streamSource.getReader()) {
resolvedSchemaSource = resolveSchema(streamSource.getPublicId(), streamSource.getSystemId());
}
} else if(sourceXSD instanceof SAXSource) {
SAXSource saxSource = (SAXSource) sourceXSD;
InputSource inputSource = saxSource.getInputSource();
if(null == inputSource) {
resolvedSchemaSource = resolveSchema(saxSource.getSystemId());
} else if(null == inputSource.getByteStream() && null == inputSource.getCharacterStream()){
resolvedSchemaSource = resolveSchema(inputSource.getPublicId(), inputSource.getSystemId());
}
} else if(sourceXSD instanceof DOMSource) {
DOMSource domSource = (DOMSource) sourceXSD;
if(null == domSource.getNode()) {
resolvedSchemaSource = resolveSchema(domSource.getSystemId());
}
} else if(null != sourceXSD.getSystemId()) {
resolvedSchemaSource = resolveSchema(sourceXSD.getSystemId());
}
if(resolvedSchemaSource != null) {
return resolvedSchemaSource;
}
return sourceXSD;
}
/**
* Allow the SchemaResolver implementation to attempt to return the referenced Schema based on
* given source schema, namespace and schemaLocation values from an import or include. If the
* resolver fails, this method will attempt to resolve the schema
*
* @param sourceXSD The Source object of the source schema
* @param namespace The namespace portion of the import/include
* @param schemaLocation The schemaLocation portion of the import/include
* @return Source for the referenced Schema or null if processing the referenced
* schema should be skipped
*/
public Source resolveSchema(Source sourceXSD, String namespace, String schemaLocation) {
// Add sourceXSD's SystemId to the processed schema list to avoid re-processing
addSchemaToList(sourceXSD.getSystemId());
Source schemaSource = schemaResolver.resolveSchema(sourceXSD, namespace, schemaLocation);
if (schemaSource != null) {
String sysId = schemaSource.getSystemId();
if (shouldProcessSchema(sysId)) {
return schemaSource;
}
}
return null;
}
public Source resolveSchema(String systemId) {
return resolveSchema(null, systemId);
}
public Source resolveSchema(String publicId, String systemId) {
if(!addSchemaToList(systemId)) {
return null;
}
try {
InputSource inputSource = schemaResolver.resolveEntity(publicId, systemId);
if(inputSource != null) {
return new SAXSource(inputSource);
}
} catch(Exception ex) {
throw SDOException.errorResolvingSchema(ex);
}
return null;
}
/**
* Indicates if the schema represented by the given systemId (schema URL string) should be processed.
* If systemId exists in the list, it should not be processed; otherwise, it will be added to the
* list and true returned to indicate processing is required.
*
* @param systemId a String that conforms to the URI syntax
* @return true if systemId is null or does not exist in the list of previously processed schemas,
* false otherwise
*/
private boolean shouldProcessSchema(String systemId) {
if (systemId == null) {
return true;
}
return addSchemaToList(systemId);
}
/**
* Add the given SystemId to the list of processed schemas, if it isn't already in the list.
*
* @param systemId a String that conforms to the URI syntax
* @return true if systemId was added to the list (hence the associated schema should be processed),
* false if the id was not added to the list or systemId is null.
*/
private boolean addSchemaToList(String systemId) {
if (systemId == null || systemIdList.contains(systemId)) {
return false;
}
systemIdList.add(systemId);
return true;
}
/**
* Return the SchemaResolver for this wrapper instance.
*
* @return
*/
public SchemaResolver getSchemaResolver() {
return schemaResolver;
}
}