< 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 >