Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/openjdk-multiarch-jdk8u
Path: blob/aarch64-shenandoah-jdk8u272-b10/jdk/src/share/classes/com/sun/naming/internal/ResourceManager.java
38923 views
1
/*
2
* Copyright (c) 1999, 2013, Oracle and/or its affiliates. All rights reserved.
3
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4
*
5
* This code is free software; you can redistribute it and/or modify it
6
* under the terms of the GNU General Public License version 2 only, as
7
* published by the Free Software Foundation. Oracle designates this
8
* particular file as subject to the "Classpath" exception as provided
9
* by Oracle in the LICENSE file that accompanied this code.
10
*
11
* This code is distributed in the hope that it will be useful, but WITHOUT
12
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14
* version 2 for more details (a copy is included in the LICENSE file that
15
* accompanied this code).
16
*
17
* You should have received a copy of the GNU General Public License version
18
* 2 along with this work; if not, write to the Free Software Foundation,
19
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20
*
21
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22
* or visit www.oracle.com if you need additional information or have any
23
* questions.
24
*/
25
26
package com.sun.naming.internal;
27
28
import java.io.InputStream;
29
import java.io.IOException;
30
import java.lang.ref.WeakReference;
31
import java.lang.reflect.Method;
32
import java.lang.reflect.InvocationTargetException;
33
import java.util.HashMap;
34
import java.util.Hashtable;
35
import java.util.Map;
36
import java.util.Properties;
37
import java.util.StringTokenizer;
38
import java.util.List;
39
import java.util.ArrayList;
40
import java.util.WeakHashMap;
41
42
import javax.naming.*;
43
44
/**
45
* The ResourceManager class facilitates the reading of JNDI resource files.
46
*
47
* @author Rosanna Lee
48
* @author Scott Seligman
49
*/
50
51
public final class ResourceManager {
52
53
/*
54
* Name of provider resource files (without the package-name prefix.)
55
*/
56
private static final String PROVIDER_RESOURCE_FILE_NAME =
57
"jndiprovider.properties";
58
59
/*
60
* Name of application resource files.
61
*/
62
private static final String APP_RESOURCE_FILE_NAME = "jndi.properties";
63
64
/*
65
* Name of properties file in <java.home>/lib.
66
*/
67
private static final String JRELIB_PROPERTY_FILE_NAME = "jndi.properties";
68
69
/*
70
* Internal environment property, that when set to "true", disables
71
* application resource files lookup to prevent recursion issues
72
* when validating signed JARs.
73
*/
74
private static final String DISABLE_APP_RESOURCE_FILES =
75
"com.sun.naming.disable.app.resource.files";
76
77
/*
78
* The standard JNDI properties that specify colon-separated lists.
79
*/
80
private static final String[] listProperties = {
81
Context.OBJECT_FACTORIES,
82
Context.URL_PKG_PREFIXES,
83
Context.STATE_FACTORIES,
84
// The following shouldn't create a runtime dependence on ldap package.
85
javax.naming.ldap.LdapContext.CONTROL_FACTORIES
86
};
87
88
private static final VersionHelper helper =
89
VersionHelper.getVersionHelper();
90
91
/*
92
* A cache of the properties that have been constructed by
93
* the ResourceManager. A Hashtable from a provider resource
94
* file is keyed on a class in the resource file's package.
95
* One from application resource files is keyed on the thread's
96
* context class loader.
97
*/
98
// WeakHashMap<Class | ClassLoader, Hashtable>
99
private static final WeakHashMap<Object, Hashtable<? super String, Object>>
100
propertiesCache = new WeakHashMap<>(11);
101
102
/*
103
* A cache of factory objects (ObjectFactory, StateFactory, ControlFactory).
104
*
105
* A two-level cache keyed first on context class loader and then
106
* on propValue. Value is a list of class or factory objects,
107
* weakly referenced so as not to prevent GC of the class loader.
108
* Used in getFactories().
109
*/
110
private static final
111
WeakHashMap<ClassLoader, Map<String, List<NamedWeakReference<Object>>>>
112
factoryCache = new WeakHashMap<>(11);
113
114
/*
115
* A cache of URL factory objects (ObjectFactory).
116
*
117
* A two-level cache keyed first on context class loader and then
118
* on classSuffix+propValue. Value is the factory itself (weakly
119
* referenced so as not to prevent GC of the class loader) or
120
* NO_FACTORY if a previous search revealed no factory. Used in
121
* getFactory().
122
*/
123
private static final
124
WeakHashMap<ClassLoader, Map<String, WeakReference<Object>>>
125
urlFactoryCache = new WeakHashMap<>(11);
126
private static final WeakReference<Object> NO_FACTORY =
127
new WeakReference<>(null);
128
129
/**
130
* A class to allow JNDI properties be specified as applet parameters
131
* without creating a static dependency on java.applet.
132
*/
133
private static class AppletParameter {
134
private static final Class<?> clazz = getClass("java.applet.Applet");
135
private static final Method getMethod =
136
getMethod(clazz, "getParameter", String.class);
137
private static Class<?> getClass(String name) {
138
try {
139
return Class.forName(name, true, null);
140
} catch (ClassNotFoundException e) {
141
return null;
142
}
143
}
144
private static Method getMethod(Class<?> clazz,
145
String name,
146
Class<?>... paramTypes)
147
{
148
if (clazz != null) {
149
try {
150
return clazz.getMethod(name, paramTypes);
151
} catch (NoSuchMethodException e) {
152
throw new AssertionError(e);
153
}
154
} else {
155
return null;
156
}
157
}
158
159
/**
160
* Returns the value of the applet's named parameter.
161
*/
162
static Object get(Object applet, String name) {
163
// if clazz is null then applet cannot be an Applet.
164
if (clazz == null || !clazz.isInstance(applet))
165
throw new ClassCastException(applet.getClass().getName());
166
try {
167
return getMethod.invoke(applet, name);
168
} catch (InvocationTargetException |
169
IllegalAccessException e) {
170
throw new AssertionError(e);
171
}
172
}
173
}
174
175
// There should be no instances of this class.
176
private ResourceManager() {
177
}
178
179
180
// ---------- Public methods ----------
181
182
/*
183
* Given the environment parameter passed to the initial context
184
* constructor, returns the full environment for that initial
185
* context (never null). This is based on the environment
186
* parameter, the applet parameters (where appropriate), the
187
* system properties, and all application resource files.
188
*
189
* <p> This method will modify <tt>env</tt> and save
190
* a reference to it. The caller may no longer modify it.
191
*
192
* @param env environment passed to initial context constructor.
193
* Null indicates an empty environment.
194
*
195
* @throws NamingException if an error occurs while reading a
196
* resource file
197
*/
198
@SuppressWarnings("unchecked")
199
public static Hashtable<?, ?> getInitialEnvironment(
200
Hashtable<?, ?> env)
201
throws NamingException
202
{
203
String[] props = VersionHelper.PROPS; // system/applet properties
204
if (env == null) {
205
env = new Hashtable<>(11);
206
}
207
Object applet = env.get(Context.APPLET);
208
209
// Merge property values from env param, applet params, and system
210
// properties. The first value wins: there's no concatenation of
211
// colon-separated lists.
212
// Read system properties by first trying System.getProperties(),
213
// and then trying System.getProperty() if that fails. The former
214
// is more efficient due to fewer permission checks.
215
//
216
String[] jndiSysProps = helper.getJndiProperties();
217
for (int i = 0; i < props.length; i++) {
218
Object val = env.get(props[i]);
219
if (val == null) {
220
if (applet != null) {
221
val = AppletParameter.get(applet, props[i]);
222
}
223
if (val == null) {
224
// Read system property.
225
val = (jndiSysProps != null)
226
? jndiSysProps[i]
227
: helper.getJndiProperty(i);
228
}
229
if (val != null) {
230
((Hashtable<String, Object>)env).put(props[i], val);
231
}
232
}
233
}
234
235
// Return without merging if application resource files lookup
236
// is disabled.
237
String disableAppRes = (String)env.get(DISABLE_APP_RESOURCE_FILES);
238
if (disableAppRes != null && disableAppRes.equalsIgnoreCase("true")) {
239
return env;
240
}
241
242
// Merge the above with the values read from all application
243
// resource files. Colon-separated lists are concatenated.
244
mergeTables((Hashtable<Object, Object>)env, getApplicationResources());
245
return env;
246
}
247
248
/**
249
* Retrieves the property from the environment, or from the provider
250
* resource file associated with the given context. The environment
251
* may in turn contain values that come from applet parameters,
252
* system properties, or application resource files.
253
*
254
* If <tt>concat</tt> is true and both the environment and the provider
255
* resource file contain the property, the two values are concatenated
256
* (with a ':' separator).
257
*
258
* Returns null if no value is found.
259
*
260
* @param propName The non-null property name
261
* @param env The possibly null environment properties
262
* @param ctx The possibly null context
263
* @param concat True if multiple values should be concatenated
264
* @return the property value, or null is there is none.
265
* @throws NamingException if an error occurs while reading the provider
266
* resource file.
267
*/
268
public static String getProperty(String propName, Hashtable<?,?> env,
269
Context ctx, boolean concat)
270
throws NamingException {
271
272
String val1 = (env != null) ? (String)env.get(propName) : null;
273
if ((ctx == null) ||
274
((val1 != null) && !concat)) {
275
return val1;
276
}
277
String val2 = (String)getProviderResource(ctx).get(propName);
278
if (val1 == null) {
279
return val2;
280
} else if ((val2 == null) || !concat) {
281
return val1;
282
} else {
283
return (val1 + ":" + val2);
284
}
285
}
286
287
/**
288
* Retrieves an enumeration of factory classes/object specified by a
289
* property.
290
*
291
* The property is gotten from the environment and the provider
292
* resource file associated with the given context and concantenated.
293
* See getProperty(). The resulting property value is a list of class names.
294
*<p>
295
* This method then loads each class using the current thread's context
296
* class loader and keeps them in a list. Any class that cannot be loaded
297
* is ignored. The resulting list is then cached in a two-level
298
* hash table, keyed first by the context class loader and then by
299
* the property's value.
300
* The next time threads of the same context class loader call this
301
* method, they can use the cached list.
302
*<p>
303
* After obtaining the list either from the cache or by creating one from
304
* the property value, this method then creates and returns a
305
* FactoryEnumeration using the list. As the FactoryEnumeration is
306
* traversed, the cached Class object in the list is instantiated and
307
* replaced by an instance of the factory object itself. Both class
308
* objects and factories are wrapped in weak references so as not to
309
* prevent GC of the class loader.
310
*<p>
311
* Note that multiple threads can be accessing the same cached list
312
* via FactoryEnumeration, which locks the list during each next().
313
* The size of the list will not change,
314
* but a cached Class object might be replaced by an instantiated factory
315
* object.
316
*
317
* @param propName The non-null property name
318
* @param env The possibly null environment properties
319
* @param ctx The possibly null context
320
* @return An enumeration of factory classes/objects; null if none.
321
* @exception NamingException If encounter problem while reading the provider
322
* property file.
323
* @see javax.naming.spi.NamingManager#getObjectInstance
324
* @see javax.naming.spi.NamingManager#getStateToBind
325
* @see javax.naming.spi.DirectoryManager#getObjectInstance
326
* @see javax.naming.spi.DirectoryManager#getStateToBind
327
* @see javax.naming.ldap.ControlFactory#getControlInstance
328
*/
329
public static FactoryEnumeration getFactories(String propName,
330
Hashtable<?,?> env, Context ctx) throws NamingException {
331
332
String facProp = getProperty(propName, env, ctx, true);
333
if (facProp == null)
334
return null; // no classes specified; return null
335
336
// Cache is based on context class loader and property val
337
ClassLoader loader = helper.getContextClassLoader();
338
339
Map<String, List<NamedWeakReference<Object>>> perLoaderCache = null;
340
synchronized (factoryCache) {
341
perLoaderCache = factoryCache.get(loader);
342
if (perLoaderCache == null) {
343
perLoaderCache = new HashMap<>(11);
344
factoryCache.put(loader, perLoaderCache);
345
}
346
}
347
348
synchronized (perLoaderCache) {
349
List<NamedWeakReference<Object>> factories =
350
perLoaderCache.get(facProp);
351
if (factories != null) {
352
// Cached list
353
return factories.size() == 0 ? null
354
: new FactoryEnumeration(factories, loader);
355
} else {
356
// Populate list with classes named in facProp; skipping
357
// those that we cannot load
358
StringTokenizer parser = new StringTokenizer(facProp, ":");
359
factories = new ArrayList<>(5);
360
while (parser.hasMoreTokens()) {
361
try {
362
// System.out.println("loading");
363
String className = parser.nextToken();
364
Class<?> c = helper.loadClass(className, loader);
365
factories.add(new NamedWeakReference<Object>(c, className));
366
} catch (Exception e) {
367
// ignore ClassNotFoundException, IllegalArgumentException
368
}
369
}
370
// System.out.println("adding to cache: " + factories);
371
perLoaderCache.put(facProp, factories);
372
return new FactoryEnumeration(factories, loader);
373
}
374
}
375
}
376
377
/**
378
* Retrieves a factory from a list of packages specified in a
379
* property.
380
*
381
* The property is gotten from the environment and the provider
382
* resource file associated with the given context and concatenated.
383
* classSuffix is added to the end of this list.
384
* See getProperty(). The resulting property value is a list of package
385
* prefixes.
386
*<p>
387
* This method then constructs a list of class names by concatenating
388
* each package prefix with classSuffix and attempts to load and
389
* instantiate the class until one succeeds.
390
* Any class that cannot be loaded is ignored.
391
* The resulting object is then cached in a two-level hash table,
392
* keyed first by the context class loader and then by the property's
393
* value and classSuffix.
394
* The next time threads of the same context class loader call this
395
* method, they use the cached factory.
396
* If no factory can be loaded, NO_FACTORY is recorded in the table
397
* so that next time it'll return quickly.
398
*
399
* @param propName The non-null property name
400
* @param env The possibly null environment properties
401
* @param ctx The possibly null context
402
* @param classSuffix The non-null class name
403
* (e.g. ".ldap.ldapURLContextFactory).
404
* @param defaultPkgPrefix The non-null default package prefix.
405
* (e.g., "com.sun.jndi.url").
406
* @return An factory object; null if none.
407
* @exception NamingException If encounter problem while reading the provider
408
* property file, or problem instantiating the factory.
409
*
410
* @see javax.naming.spi.NamingManager#getURLContext
411
* @see javax.naming.spi.NamingManager#getURLObject
412
*/
413
public static Object getFactory(String propName, Hashtable<?,?> env,
414
Context ctx, String classSuffix, String defaultPkgPrefix)
415
throws NamingException {
416
417
// Merge property with provider property and supplied default
418
String facProp = getProperty(propName, env, ctx, true);
419
if (facProp != null)
420
facProp += (":" + defaultPkgPrefix);
421
else
422
facProp = defaultPkgPrefix;
423
424
// Cache factory based on context class loader, class name, and
425
// property val
426
ClassLoader loader = helper.getContextClassLoader();
427
String key = classSuffix + " " + facProp;
428
429
Map<String, WeakReference<Object>> perLoaderCache = null;
430
synchronized (urlFactoryCache) {
431
perLoaderCache = urlFactoryCache.get(loader);
432
if (perLoaderCache == null) {
433
perLoaderCache = new HashMap<>(11);
434
urlFactoryCache.put(loader, perLoaderCache);
435
}
436
}
437
438
synchronized (perLoaderCache) {
439
Object factory = null;
440
441
WeakReference<Object> factoryRef = perLoaderCache.get(key);
442
if (factoryRef == NO_FACTORY) {
443
return null;
444
} else if (factoryRef != null) {
445
factory = factoryRef.get();
446
if (factory != null) { // check if weak ref has been cleared
447
return factory;
448
}
449
}
450
451
// Not cached; find first factory and cache
452
StringTokenizer parser = new StringTokenizer(facProp, ":");
453
String className;
454
while (factory == null && parser.hasMoreTokens()) {
455
className = parser.nextToken() + classSuffix;
456
try {
457
// System.out.println("loading " + className);
458
factory = helper.loadClass(className, loader).newInstance();
459
} catch (InstantiationException e) {
460
NamingException ne =
461
new NamingException("Cannot instantiate " + className);
462
ne.setRootCause(e);
463
throw ne;
464
} catch (IllegalAccessException e) {
465
NamingException ne =
466
new NamingException("Cannot access " + className);
467
ne.setRootCause(e);
468
throw ne;
469
} catch (Exception e) {
470
// ignore ClassNotFoundException, IllegalArgumentException,
471
// etc.
472
}
473
}
474
475
// Cache it.
476
perLoaderCache.put(key, (factory != null)
477
? new WeakReference<>(factory)
478
: NO_FACTORY);
479
return factory;
480
}
481
}
482
483
484
// ---------- Private methods ----------
485
486
/*
487
* Returns the properties contained in the provider resource file
488
* of an object's package. Returns an empty hash table if the
489
* object is null or the resource file cannot be found. The
490
* results are cached.
491
*
492
* @throws NamingException if an error occurs while reading the file.
493
*/
494
private static Hashtable<? super String, Object>
495
getProviderResource(Object obj)
496
throws NamingException
497
{
498
if (obj == null) {
499
return (new Hashtable<>(1));
500
}
501
synchronized (propertiesCache) {
502
Class<?> c = obj.getClass();
503
504
Hashtable<? super String, Object> props =
505
propertiesCache.get(c);
506
if (props != null) {
507
return props;
508
}
509
props = new Properties();
510
511
InputStream istream =
512
helper.getResourceAsStream(c, PROVIDER_RESOURCE_FILE_NAME);
513
514
if (istream != null) {
515
try {
516
((Properties)props).load(istream);
517
} catch (IOException e) {
518
NamingException ne = new ConfigurationException(
519
"Error reading provider resource file for " + c);
520
ne.setRootCause(e);
521
throw ne;
522
}
523
}
524
propertiesCache.put(c, props);
525
return props;
526
}
527
}
528
529
530
/*
531
* Returns the Hashtable (never null) that results from merging
532
* all application resource files available to this thread's
533
* context class loader. The properties file in <java.home>/lib
534
* is also merged in. The results are cached.
535
*
536
* SECURITY NOTES:
537
* 1. JNDI needs permission to read the application resource files.
538
* 2. Any class will be able to use JNDI to view the contents of
539
* the application resource files in its own classpath. Give
540
* careful consideration to this before storing sensitive
541
* information there.
542
*
543
* @throws NamingException if an error occurs while reading a resource
544
* file.
545
*/
546
private static Hashtable<? super String, Object> getApplicationResources()
547
throws NamingException {
548
549
ClassLoader cl = helper.getContextClassLoader();
550
551
synchronized (propertiesCache) {
552
Hashtable<? super String, Object> result = propertiesCache.get(cl);
553
if (result != null) {
554
return result;
555
}
556
557
try {
558
NamingEnumeration<InputStream> resources =
559
helper.getResources(cl, APP_RESOURCE_FILE_NAME);
560
try {
561
while (resources.hasMore()) {
562
Properties props = new Properties();
563
InputStream istream = resources.next();
564
try {
565
props.load(istream);
566
} finally {
567
istream.close();
568
}
569
570
if (result == null) {
571
result = props;
572
} else {
573
mergeTables(result, props);
574
}
575
}
576
} finally {
577
while (resources.hasMore()) {
578
resources.next().close();
579
}
580
}
581
582
// Merge in properties from file in <java.home>/lib.
583
InputStream istream =
584
helper.getJavaHomeLibStream(JRELIB_PROPERTY_FILE_NAME);
585
if (istream != null) {
586
try {
587
Properties props = new Properties();
588
props.load(istream);
589
590
if (result == null) {
591
result = props;
592
} else {
593
mergeTables(result, props);
594
}
595
} finally {
596
istream.close();
597
}
598
}
599
600
} catch (IOException e) {
601
NamingException ne = new ConfigurationException(
602
"Error reading application resource file");
603
ne.setRootCause(e);
604
throw ne;
605
}
606
if (result == null) {
607
result = new Hashtable<>(11);
608
}
609
propertiesCache.put(cl, result);
610
return result;
611
}
612
}
613
614
/*
615
* Merge the properties from one hash table into another. Each
616
* property in props2 that is not in props1 is added to props1.
617
* For each property in both hash tables that is one of the
618
* standard JNDI properties that specify colon-separated lists,
619
* the values are concatenated and stored in props1.
620
*/
621
private static void mergeTables(Hashtable<? super String, Object> props1,
622
Hashtable<? super String, Object> props2) {
623
for (Object key : props2.keySet()) {
624
String prop = (String)key;
625
Object val1 = props1.get(prop);
626
if (val1 == null) {
627
props1.put(prop, props2.get(prop));
628
} else if (isListProperty(prop)) {
629
String val2 = (String)props2.get(prop);
630
props1.put(prop, ((String)val1) + ":" + val2);
631
}
632
}
633
}
634
635
/*
636
* Is a property one of the standard JNDI properties that specify
637
* colon-separated lists?
638
*/
639
private static boolean isListProperty(String prop) {
640
prop = prop.intern();
641
for (int i = 0; i < listProperties.length; i++) {
642
if (prop == listProperties[i]) {
643
return true;
644
}
645
}
646
return false;
647
}
648
}
649
650