< prev index next >
src/java.base/unix/classes/java/lang/ProcessEnvironment.java
Print this page
*** 1,7 ****
/*
! * Copyright (c) 2003, 2011, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
--- 1,7 ----
/*
! * Copyright (c) 2003, 2017, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
*** 52,85 ****
* @since 1.5
*/
package java.lang;
! import java.io.*;
! import java.util.*;
!
final class ProcessEnvironment
{
- private static final HashMap<Variable,Value> theEnvironment;
- private static final Map<String,String> theUnmodifiableEnvironment;
static final int MIN_NAME_LENGTH = 0;
static {
// We cache the C environment. This means that subsequent calls
! // to putenv/setenv from C will not be visible from Java code.
byte[][] environ = environ();
! theEnvironment = new HashMap<>(environ.length/2 + 3);
// Read environment variables back to front,
// so that earlier variables override later ones.
for (int i = environ.length-1; i > 0; i-=2)
! theEnvironment.put(Variable.valueOf(environ[i-1]),
Value.valueOf(environ[i]));
! theUnmodifiableEnvironment
! = Collections.unmodifiableMap
! (new StringEnvironment(theEnvironment));
}
/* Only for use by System.getenv(String) */
static String getenv(String name) {
return theUnmodifiableEnvironment.get(name);
--- 52,128 ----
* @since 1.5
*/
package java.lang;
! import java.lang.invoke.MethodHandles;
! import java.lang.invoke.VarHandle;
! import java.util.AbstractCollection;
! import java.util.AbstractMap;
! import java.util.AbstractSet;
! import java.util.Collection;
! import java.util.Collections;
! import java.util.HashMap;
! import java.util.Iterator;
! import java.util.Map;
! import java.util.Set;
final class ProcessEnvironment
{
static final int MIN_NAME_LENGTH = 0;
+ private static final VarHandle THE_ENVIRONMENT;
+ // must only be accessed through the VarHandle
+ private static HashMap<Variable,Value> theEnvironment = readSystemEnv();
+
static {
+ try {
+ MethodHandles.Lookup l = MethodHandles.lookup();
+ THE_ENVIRONMENT = l.findStaticVarHandle(ProcessEnvironment.class,
+ "theEnvironment",
+ HashMap.class);
+ } catch (ReflectiveOperationException e) {
+ throw new Error(e);
+ }
+ }
+
+ // The underlying map must be accessed through this getter.
+ private static HashMap<Variable,Value> getTheEnvironment() {
+ return (HashMap<Variable,Value>)THE_ENVIRONMENT.getAcquire();
+ }
+
+ // Used by refreshEnv to update the underlying env variables map.
+ private static void setTheEnvironment(Map<Variable,Value> newMap) {
+ THE_ENVIRONMENT.setRelease(newMap);
+ }
+
+ private static final AbstractStringEnvironment theStringEnvironment =
+ new TheStringEnvironment();
+ private static final Map<String,String> theUnmodifiableEnvironment =
+ Collections.unmodifiableMap(theStringEnvironment);
+
+ private static HashMap<Variable,Value> readSystemEnv() {
// We cache the C environment. This means that subsequent calls
! // to putenv/setenv from C will not be visible from Java code,
! // unless {@link #refreshEnv} is invoke.
byte[][] environ = environ();
! HashMap<Variable,Value> map = new HashMap<>((4 * environ.length) / 3);
// Read environment variables back to front,
// so that earlier variables override later ones.
for (int i = environ.length-1; i > 0; i-=2)
! map.put(Variable.valueOf(environ[i-1]),
Value.valueOf(environ[i]));
+ return map;
+ }
! /* Only used System.refreshEnv() */
! static void refreshEnv() {
! HashMap<Variable,Value> newMap = readSystemEnv();
! // only one thread can update at a time
! synchronized (theStringEnvironment) {
! setTheEnvironment(newMap);
! }
}
/* Only for use by System.getenv(String) */
static String getenv(String name) {
return theUnmodifiableEnvironment.get(name);
*** 92,102 ****
/* Only for use by ProcessBuilder.environment() */
@SuppressWarnings("unchecked")
static Map<String,String> environment() {
return new StringEnvironment
! ((Map<Variable,Value>)(theEnvironment.clone()));
}
/* Only for use by Runtime.exec(...String[]envp...) */
static Map<String,String> emptyEnvironment(int capacity) {
return new StringEnvironment(new HashMap<>(capacity));
--- 135,145 ----
/* Only for use by ProcessBuilder.environment() */
@SuppressWarnings("unchecked")
static Map<String,String> environment() {
return new StringEnvironment
! ((Map<Variable,Value>)(getTheEnvironment().clone()));
}
/* Only for use by Runtime.exec(...String[]envp...) */
static Map<String,String> emptyEnvironment(int capacity) {
return new StringEnvironment(new HashMap<>(capacity));
*** 216,275 ****
return o instanceof Value && super.equals(o);
}
}
// This implements the String map view the user sees.
! private static class StringEnvironment
extends AbstractMap<String,String>
{
! private Map<Variable,Value> m;
private static String toString(Value v) {
return v == null ? null : v.toString();
}
! public StringEnvironment(Map<Variable,Value> m) {this.m = m;}
! public int size() {return m.size();}
! public boolean isEmpty() {return m.isEmpty();}
! public void clear() { m.clear();}
public boolean containsKey(Object key) {
! return m.containsKey(Variable.valueOfQueryOnly(key));
}
public boolean containsValue(Object value) {
! return m.containsValue(Value.valueOfQueryOnly(value));
}
public String get(Object key) {
! return toString(m.get(Variable.valueOfQueryOnly(key)));
}
public String put(String key, String value) {
! return toString(m.put(Variable.valueOf(key),
Value.valueOf(value)));
}
public String remove(Object key) {
! return toString(m.remove(Variable.valueOfQueryOnly(key)));
}
public Set<String> keySet() {
! return new StringKeySet(m.keySet());
}
public Set<Map.Entry<String,String>> entrySet() {
! return new StringEntrySet(m.entrySet());
}
public Collection<String> values() {
! return new StringValues(m.values());
}
// It is technically feasible to provide a byte-oriented view
// as follows:
// public Map<byte[],byte[]> asByteArrayMap() {
! // return new ByteArrayEnvironment(m);
// }
// Convert to Unix style environ as a monolithic byte array
// inspired by the Windows Environment Block, except we work
// exclusively with bytes instead of chars, and we need only
// one trailing NUL on Unix.
// This keeps the JNI as simple and efficient as possible.
public byte[] toEnvironmentBlock(int[]envc) {
int count = m.size() * 2; // For added '=' and NUL
for (Map.Entry<Variable,Value> entry : m.entrySet()) {
count += entry.getKey().getBytes().length;
count += entry.getValue().getBytes().length;
}
--- 259,319 ----
return o instanceof Value && super.equals(o);
}
}
// This implements the String map view the user sees.
! private static abstract class AbstractStringEnvironment
extends AbstractMap<String,String>
{
! protected abstract Map<Variable,Value> getMap();
!
private static String toString(Value v) {
return v == null ? null : v.toString();
}
! public int size() {return getMap().size();}
! public boolean isEmpty() {return getMap().isEmpty();}
! public void clear() { getMap().clear();}
public boolean containsKey(Object key) {
! return getMap().containsKey(Variable.valueOfQueryOnly(key));
}
public boolean containsValue(Object value) {
! return getMap().containsValue(Value.valueOfQueryOnly(value));
}
public String get(Object key) {
! return toString(getMap().get(Variable.valueOfQueryOnly(key)));
}
public String put(String key, String value) {
! return toString(getMap().put(Variable.valueOf(key),
Value.valueOf(value)));
}
public String remove(Object key) {
! return toString(getMap().remove(Variable.valueOfQueryOnly(key)));
}
public Set<String> keySet() {
! return new StringKeySet(getMap().keySet());
}
public Set<Map.Entry<String,String>> entrySet() {
! return new StringEntrySet(getMap().entrySet());
}
public Collection<String> values() {
! return new StringValues(getMap().values());
}
// It is technically feasible to provide a byte-oriented view
// as follows:
// public Map<byte[],byte[]> asByteArrayMap() {
! // return new ByteArrayEnvironment(getMap());
// }
// Convert to Unix style environ as a monolithic byte array
// inspired by the Windows Environment Block, except we work
// exclusively with bytes instead of chars, and we need only
// one trailing NUL on Unix.
// This keeps the JNI as simple and efficient as possible.
public byte[] toEnvironmentBlock(int[]envc) {
+ Map<Variable,Value> m = getMap();
int count = m.size() * 2; // For added '=' and NUL
for (Map.Entry<Variable,Value> entry : m.entrySet()) {
count += entry.getKey().getBytes().length;
count += entry.getValue().getBytes().length;
}
*** 291,300 ****
--- 335,362 ----
envc[0] = m.size();
return block;
}
}
+ private static class TheStringEnvironment extends AbstractStringEnvironment {
+ @Override
+ protected Map<Variable, Value> getMap() {
+ return ProcessEnvironment.getTheEnvironment();
+ }
+ }
+
+ private static class StringEnvironment extends AbstractStringEnvironment {
+ private final Map<Variable,Value> m;
+ StringEnvironment(Map<Variable,Value> map) {
+ this.m = map;
+ }
+ @Override
+ protected Map<Variable, Value> getMap() {
+ return m;
+ }
+ }
+
static byte[] toEnvironmentBlock(Map<String,String> map, int[]envc) {
return map == null ? null :
((StringEnvironment)map).toEnvironmentBlock(envc);
}
< prev index next >