File: XMLMetadataSource.java

package info (click to toggle)
eclipselink 2.7.11-1
  • links: PTS, VCS
  • area: main
  • in suites: bookworm
  • size: 44,820 kB
  • sloc: java: 477,843; xml: 503; makefile: 21
file content (228 lines) | stat: -rw-r--r-- 9,691 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
/*
 * Copyright (c) 1998, 2018 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.security.AccessController;
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.security.PrivilegedAccessHelper;
import org.eclipse.persistence.internal.security.PrivilegedGetSystemProperty;
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 {

    /**
     * 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 properties
     * @param classLoader
     * @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
     */
    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
     */
    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
     * @param properties
     * @param log
     * @return
     */
    public Object getConfigPropertyLogDebug(final String propertyName, Map properties, SessionLog log) {
        Object value = null;
        if (properties != null) {
            value = properties.get(propertyName);
        }
        if (value == null) {
            if (PrivilegedAccessHelper.shouldUsePrivilegedAccess()) {
                value = AccessController.doPrivileged(new PrivilegedGetSystemProperty(propertyName));
            } else {
                value = System.getProperty(propertyName);
            }
        }
        if ((value != null) && (log !=  null)) {
            log.log(SessionLog.FINEST, SessionLog.PROPERTIES, "property_value_specified", new Object[]{propertyName, value});
        }
        return value;
    }
}