| /* |
| * Copyright (c) 1998, 2021 Oracle and/or its affiliates. All rights reserved. |
| * Copyright (c) 1998, 2018 IBM Corporation. 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: |
| // 05/05/2011-2.3 Chris Delahunt |
| // - 344837: Extensibility - Metadata Repository |
| // 08/29/2016 Jody Grassel |
| // - 500441: Eclipselink core has System.getProperty() calls that are not potentially executed under doPriv() |
| package org.eclipse.persistence.jpa.metadata; |
| |
| import java.io.IOException; |
| |
| import java.io.InputStreamReader; |
| import java.io.Reader; |
| import java.net.URL; |
| import java.util.Enumeration; |
| import java.util.HashMap; |
| import java.util.Map; |
| import java.util.Properties; |
| |
| import org.eclipse.persistence.internal.jpa.metadata.xml.XMLEntityMappingsReader; |
| import org.eclipse.persistence.internal.jpa.metadata.xml.XMLEntityMappings; |
| |
| import org.eclipse.persistence.config.PersistenceUnitProperties; |
| import org.eclipse.persistence.exceptions.ValidationException; |
| import org.eclipse.persistence.logging.SessionLog; |
| |
| /** |
| * <p><b>Purpose</b>: Support reading metadata for a persistence unit in an XML format from a URL and if the property is undefined, |
| * it will look for a file. |
| */ |
| public class XMLMetadataSource extends MetadataSourceAdapter { |
| |
| /** |
| * Default constructor. |
| */ |
| public XMLMetadataSource() { |
| } |
| |
| /** |
| * This method returns a Reader for an EclipseLink-ORM.xml. It will use the |
| * PersistenceUnitProperties.METADATA_SOURCE_XML_URL property if available to create an |
| * InputStreamReader from a URL, and if not available, use the |
| * PersistenceUnitProperties.METADATA_SOURCE_XML_FILE property will be used to get a file |
| * resource from the classloader. |
| * It will throw a ValidationException if no reader can be returned. |
| * |
| * @param log - SessionLog used for status messages. |
| * @return Reader - a InputStreamReader with data in the form of an EclipseLink-orm.xml |
| * |
| * |
| * @see #getEntityMappings |
| */ |
| public Reader getEntityMappingsReader(Map<String, Object> properties, ClassLoader classLoader, SessionLog log) { |
| InputStreamReader reader = null; |
| |
| //read from a URL |
| String mappingURLName = (String)getConfigPropertyLogDebug( |
| PersistenceUnitProperties.METADATA_SOURCE_XML_URL, |
| properties, log); |
| if (mappingURLName !=null && mappingURLName.length()!=0) { |
| try { |
| URL url = new URL(mappingURLName); |
| reader = new InputStreamReader(url.openStream()); |
| |
| } catch (IOException exception) { |
| throw ValidationException.fileError(exception); |
| } |
| } |
| |
| //read a file using the classloader |
| if (reader == null) { |
| String mappingFileName = (String)getConfigPropertyLogDebug( |
| PersistenceUnitProperties.METADATA_SOURCE_XML_FILE, |
| properties, log); |
| if (mappingFileName != null && mappingFileName.length() > 0) { |
| try { |
| URL fileURL = getFileURL(mappingFileName, classLoader, log); |
| if (fileURL != null) { |
| reader = new InputStreamReader(fileURL.openStream()); |
| } |
| } catch (IOException exception) { |
| throw ValidationException.fileError(exception); |
| } |
| } |
| } |
| if (reader == null) { |
| //being configured to use XMLMetadataSource and not having a source to read from should be an exception |
| throw ValidationException.missingXMLMetadataRepositoryConfig(); |
| } |
| return reader; |
| } |
| |
| /** |
| * This method is responsible for returning the object representation of the MetadataSource. |
| * This implementation makes a call to getEntityMappingsReader to get a Reader which is passed to an |
| * XMLUnmarshaller, and closes the reader in a finally block. |
| * |
| * @return XMLEntityMappings - object representation of the EclipseLink-orm.xml for this repository |
| */ |
| @Override |
| public XMLEntityMappings getEntityMappings(Map<String, Object> properties, ClassLoader classLoader, SessionLog log) { |
| Reader reader = getEntityMappingsReader(properties, classLoader, log); |
| if (reader == null) { |
| return null; |
| } |
| try { |
| return XMLEntityMappingsReader.read(getRepositoryName(), reader, classLoader, properties); |
| } finally { |
| if (reader!=null) { |
| try { |
| reader.close(); |
| } catch (Exception e) { |
| //ignore so we rethrow original exception if there was one. |
| } |
| } |
| } |
| } |
| |
| /** |
| * Used by getEntityMappings when creating the XMLEntityMappings as a way of describing where it was read from. |
| * Currently returns the current class's simple name. |
| * |
| * @return String - repository name to store in the XMLEntityMappings returned from getEntityMappings |
| */ |
| public String getRepositoryName() { |
| return getClass().getSimpleName(); |
| } |
| |
| /** |
| * PUBLIC: This method is responsible for returning additional persistence |
| * unit property overrides. It is called on initial deployment of the |
| * persistence unit and when the persistence unit is reloaded to allow |
| * customization of the persistence unit above and beyond what is packaged |
| * in the persistence.xml and what is code into the application. |
| * <p> |
| * <b>IMPORTANT</b>: Although any property can be changed using this |
| * approach it is important that users of this feature ensure compatible |
| * configurations are supplied. As an example; overriding an application to |
| * use RESOURCE_LOCAL when it was coded to use JTA would result in changes |
| * not be written to the database. |
| * |
| * PersistenceUnitProperties.METADATA_SOURCE_PROPERTIES_FILE property will be used to get a file |
| * resource from the classloader. Properties are read from the file. |
| * If the property either not specified or contains an empty string then returns null. |
| * |
| * @since EclipseLink 2.4 |
| */ |
| @Override |
| public Map<String, Object> getPropertyOverrides(Map<String, Object> properties, ClassLoader classLoader, SessionLog log) { |
| String propertiesFileName = (String)getConfigPropertyLogDebug( |
| PersistenceUnitProperties.METADATA_SOURCE_PROPERTIES_FILE, |
| properties, log); |
| if (propertiesFileName == null || propertiesFileName.length() == 0) { |
| return null; |
| } |
| |
| try { |
| URL fileURL = getFileURL(propertiesFileName, classLoader, log); |
| if (fileURL != null) { |
| Properties propertiesFromFile = new Properties(); |
| propertiesFromFile.load(fileURL.openStream()); |
| if (!propertiesFromFile.isEmpty()) { |
| return new HashMap(propertiesFromFile); |
| } else { |
| return null; |
| } |
| } else { |
| throw ValidationException.missingPropertiesFileForMetadataRepositoryConfig(propertiesFileName); |
| } |
| } catch (IOException exception) { |
| throw ValidationException.fileError(exception); |
| } |
| } |
| |
| protected static URL getFileURL(String fileName, ClassLoader classLoader, SessionLog log) throws IOException { |
| Enumeration<URL> fileURLs = classLoader.getResources(fileName); |
| |
| if (!fileURLs.hasMoreElements()){ |
| fileURLs = classLoader.getResources("/./" + fileName); |
| } |
| |
| if (fileURLs.hasMoreElements()) { |
| URL nextURL = fileURLs.nextElement(); |
| if (fileURLs.hasMoreElements()) { |
| // Switched to warning, same file can be on the classpath twice in some deployments, |
| // should not be an error. |
| log.logThrowable(SessionLog.FINER, SessionLog.METADATA, ValidationException.nonUniqueRepositoryFileName(fileName)); |
| } |
| return nextURL; |
| } else { |
| return null; |
| } |
| } |
| |
| /** |
| * Check the provided map for an object with the given name. If that object is not available, check the |
| * System properties. Log the value returned if logging is enabled |
| * @param propertyName property name |
| * @param properties properties |
| * @param log logger |
| * @return object for the given name, null if not found |
| */ |
| public Object getConfigPropertyLogDebug(final String propertyName, Map<String, ?> properties, SessionLog log) { |
| return PropertyHelper.getConfigPropertyLogDebug(propertyName, properties, log); |
| } |
| } |