001/* 002 * This file is part of McIDAS-V 003 * 004 * Copyright 2007-2025 005 * Space Science and Engineering Center (SSEC) 006 * University of Wisconsin - Madison 007 * 1225 W. Dayton Street, Madison, WI 53706, USA 008 * https://www.ssec.wisc.edu/mcidas/ 009 * 010 * All Rights Reserved 011 * 012 * McIDAS-V is built on Unidata's IDV and SSEC's VisAD libraries, and 013 * some McIDAS-V source code is based on IDV and VisAD source code. 014 * 015 * McIDAS-V is free software; you can redistribute it and/or modify 016 * it under the terms of the GNU Lesser Public License as published by 017 * the Free Software Foundation; either version 3 of the License, or 018 * (at your option) any later version. 019 * 020 * McIDAS-V is distributed in the hope that it will be useful, 021 * but WITHOUT ANY WARRANTY; without even the implied warranty of 022 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 023 * GNU Lesser Public License for more details. 024 * 025 * You should have received a copy of the GNU Lesser Public License 026 * along with this program. If not, see https://www.gnu.org/licenses/. 027 */ 028 029package edu.wisc.ssec.mcidasv.util; 030 031import java.util.Map; 032import java.util.Objects; 033import java.util.concurrent.ConcurrentHashMap; 034 035import org.python.core.Py; 036import org.python.core.PyObject; 037import org.python.core.PyString; 038import org.python.core.PyStringMap; 039 040public class LoudPyStringMap extends PyStringMap { 041 042 private final String mapName; 043 044 private Map<Object, PyObject> initMap; 045 046 public LoudPyStringMap(String name) { 047 mapName = name; 048 } 049 050 public void bake() { 051 if (initMap == null) { 052 initMap = new ConcurrentHashMap<>(this.getMap()); 053 } 054 } 055 056 private boolean isAlwaysAllowed(String key) { 057 // __package__ 058 // __doc__ 059 // __name__ 060 // __builtins__ 061 return Objects.equals(key, "__builtins__") 062 || Objects.equals(key, "__doc__") 063 || Objects.equals(key, "__name__") 064 || Objects.equals(key, "__package__"); 065 } 066 067 private boolean isAlwaysAllowed(PyObject key) { 068 String str = key.toString(); 069 return isAlwaysAllowed(str); 070 } 071 072 private boolean checkForDone(Map<Object, PyObject> table) { 073 boolean result = false; 074 if (table.containsKey("___init_finished")) { 075 result = Py.py2boolean(table.get("___init_finished")); 076 } 077 return result; 078 } 079 080 @Override public PyObject __getitem__(String key) { 081 if (isAlwaysAllowed(key)) { 082 return super.__getitem__(key); 083 } 084 Map<Object, PyObject> table = getMap(); 085 if ((initMap == null) && checkForDone(table)) { 086 bake(); 087 } 088// if (initMap != null) { 089// return initMap.get(key); 090// } else { 091// return super.__getitem__(key); 092// } 093 return super.__getitem__(key); 094 } 095 096 @Override public PyObject __getitem__(PyObject key) { 097 if (isAlwaysAllowed(key)) { 098 return super.__getitem__(key); 099 } 100 Map<Object, PyObject> table = getMap(); 101 if ((initMap == null) && checkForDone(table)) { 102 bake(); 103 } 104 105// if (initMap != null) { 106// return initMap.get(pyToKey(key)); 107// } else { 108// return super.__getitem__(key); 109// } 110 return super.__getitem__(key); 111 } 112 113 @Override public PyObject __iter__() { 114 Map<Object, PyObject> table = getMap(); 115 if ((initMap == null) && checkForDone(table)) { 116 bake(); 117 } 118 return super.__iter__(); 119 } 120 121 @Override public void __setitem__(String key, PyObject value) { 122 if (isAlwaysAllowed(key)) { 123 super.__setitem__(key, value); 124 return; 125 } 126 Map<Object, PyObject> table = getMap(); 127 if ((initMap == null) && checkForDone(table)) { 128 bake(); 129 } 130// boolean fromInit = false; 131// if (initMap != null) { 132// fromInit = initMap.containsKey(key); 133// } 134// 135// if (!fromInit) { 136// super.__setitem__(key, value); 137// } 138 super.__setitem__(key, value); 139 } 140 141 @Override public void __setitem__(PyObject key, PyObject value) { 142 if (isAlwaysAllowed(key)) { 143 super.__setitem__(key, value); 144 return; 145 } 146 Map<Object, PyObject> table = getMap(); 147 if ((initMap == null) && checkForDone(table)) { 148 bake(); 149 } 150// Object convert = pyToKey(key); 151// boolean fromInit = false; 152// if (initMap != null) { 153// fromInit = initMap.containsKey(convert); 154// } 155// 156// if (!fromInit) { 157// super.__setitem__(key, value); 158// } 159 super.__setitem__(key, value); 160 } 161 162 @Override public void __delitem__(String key) { 163 if (isAlwaysAllowed(key)) { 164 super.__delitem__(key); 165 return; 166 } 167 Map<Object, PyObject> table = getMap(); 168 if ((initMap == null) && checkForDone(table)) { 169 bake(); 170 } 171// boolean fromInit = false; 172// if (initMap != null) { 173// fromInit = initMap.containsKey(key); 174// } 175// 176// if (!fromInit) { 177// super.__delitem__(key); 178// } 179 super.__delitem__(key); 180 } 181 182 @Override public void __delitem__(PyObject key) { 183 if (isAlwaysAllowed(key)) { 184 super.__delitem__(key); 185 return; 186 } 187 Map<Object, PyObject> table = getMap(); 188 if ((initMap == null) && checkForDone(table)) { 189 bake(); 190 } 191// Object convert = pyToKey(key); 192// boolean fromInit = false; 193// if (initMap != null) { 194// fromInit = initMap.containsKey(convert); 195// } 196// 197// if (!fromInit) { 198// super.__delitem__(key); 199// } 200 super.__delitem__(key); 201 } 202 203 private static PyObject keyToPy(Object objKey){ 204 if (objKey instanceof String) { 205 return PyString.fromInterned((String)objKey); 206 } else { 207 return (PyObject)objKey; 208 } 209 } 210 211 private static Object pyToKey(PyObject pyKey) { 212 if (pyKey instanceof PyString) { 213 return ((PyString)pyKey).internedString(); 214 } else { 215 return pyKey; 216 } 217 } 218}