001/* 002 * This file is part of McIDAS-V 003 * 004 * Copyright 2007-2016 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 http://www.gnu.org/licenses. 027 */ 028 029package edu.wisc.ssec.mcidasv.util; 030 031import static java.util.Objects.requireNonNull; 032 033import org.python.core.Py; 034import org.python.core.PyDictProxy; 035import org.python.core.PyDictionary; 036import org.python.core.PyDictionaryDerived; 037import org.python.core.PyObject; 038import org.python.core.PyString; 039import org.python.core.PyTuple; 040import ucar.unidata.idv.IdvObjectStore; 041 042import edu.wisc.ssec.mcidasv.McIDASV; 043 044import java.util.ArrayList; 045import java.util.HashMap; 046import java.util.LinkedHashMap; 047import java.util.List; 048import java.util.Map; 049import java.util.Set; 050import java.util.TreeSet; 051 052/** 053 * Wraps the application's {@link ucar.unidata.idv.IdvObjectStore} object and 054 * provides methods that are safe to use from Jython scripts. 055 * 056 * <p>A secondary aim of this class is to be largely API-compatible with 057 * {@code java.util.prefs.Preferences}.</p> 058 */ 059public class JythonObjectStore { 060 061 /** {@code IdvObjectStore} used by the current McIDAS-V session. */ 062 private final IdvObjectStore idvStore; 063 064 /** 065 * Return a new {@code JythonObjectStore} instance. 066 * 067 * <p>Use this method rather than the constructor.</p> 068 * 069 * @param mcidasv McIDAS-V instance that represents current session. Cannot 070 * be {@code null}. 071 * 072 * @return New instance of the {@code JythonObjectStore} class. 073 * 074 * @throws NullPointerException if {@code mcidasv} is {@code null}. 075 */ 076 public static JythonObjectStore newInstance(final McIDASV mcidasv) { 077 return new JythonObjectStore(requireNonNull(mcidasv.getStore())); 078 } 079 080 /** 081 * Create a new {@code JythonObjectStore} wrapper object. 082 * 083 * @param store McIDAS-V object store. Cannot be {@code null}. 084 * 085 * @throws NullPointerException if {@code store} is {@code null}. 086 */ 087 private JythonObjectStore(IdvObjectStore store) { 088 idvStore = requireNonNull(store); 089 } 090 091 /** 092 * Removes the value associated with the given {@code key} (if any). 093 * 094 * @param key Key whose associated value is to be removed. Cannot be 095 * {@code null}. 096 * 097 * @throws NullPointerException if {@code key} is {@code null}. 098 */ 099 public void remove(String key) { 100 idvStore.remove(requireNonNull(key)); 101 } 102 103 /** 104 * Returns the object associated with the given {@code key}. If {@code key} 105 * does not exist, {@code defaultValue} is returned. 106 * 107 * @param <T> Type of object that will be returned. 108 * @param key Key whose associated object is to be returned. 109 * Cannot be {@code null}. 110 * @param defaultValue Value to be returned if {@code key} is not valid. 111 * {@code null} is allowed. 112 * 113 * @return Object associated with {@code key} or {@code defaultValue} if 114 * {@code key} is not valid. 115 * 116 * @throws NullPointerException if {@code key} is {@code null}. 117 */ 118 public <T> T getObject(String key, T defaultValue) { 119 T storedValue = (T)idvStore.get(requireNonNull(key)); 120 if (storedValue == null) { 121 storedValue = defaultValue; 122 } 123 return storedValue; 124 } 125 126 /** 127 * Returns the {@code short} value associated with the given {@code key}. 128 * If {@code key} does not exist, {@code defaultValue} is returned. 129 * 130 * @param key Key whose associated {@code short} value is to be returned. 131 * Cannot be {@code null}. 132 * @param defaultValue Value to be returned if {@code key} is not valid. 133 * 134 * @return {@code short} value associated with {@code key} or 135 * {@code defaultValue} if {@code key} is not valid. 136 * 137 * @throws NullPointerException if {@code key} is {@code null}. 138 */ 139 public short getShort(String key, short defaultValue) { 140 return idvStore.get(requireNonNull(key), defaultValue); 141 } 142 143 /** 144 * Returns the {@code char} value associated with the given {@code key}. 145 * If {@code key} does not exist, {@code defaultValue} is returned. 146 * 147 * @param key Key whose associated {@code char} value is to be returned. 148 * Cannot be {@code null}. 149 * @param defaultValue Value to be returned if {@code key} is not valid. 150 * 151 * @return {@code char} value associated with {@code key} or 152 * {@code defaultValue} if {@code key} is not valid. 153 * 154 * @throws NullPointerException if {@code key} is {@code null}. 155 */ 156 public char getCharacter(String key, char defaultValue) { 157 return idvStore.get(requireNonNull(key), defaultValue); 158 } 159 160 /** 161 * Returns the {@code String} value associated with the given {@code key}. 162 * If {@code key} does not exist, {@code defaultValue} is returned. 163 * 164 * @param key Key whose associated {@code String} value is to be returned. 165 * Cannot be {@code null}. 166 * @param defaultValue Value to be returned if {@code key} is not valid. 167 * 168 * @return {@code String} value associated with {@code key} or 169 * {@code defaultValue} if {@code key} is not valid. 170 * 171 * @throws NullPointerException if {@code key} is {@code null}. 172 */ 173 public String getString(String key, String defaultValue) { 174 return idvStore.get(requireNonNull(key), defaultValue); 175 } 176 177 /** 178 * Returns the {@code boolean} value associated with the given {@code key}. 179 * If {@code key} does not exist, {@code defaultValue} is returned. 180 * 181 * @param key Key whose associated {@code boolean} value is to be returned. 182 * Cannot be {@code null}. 183 * @param defaultValue Value to be returned if {@code key} is not valid. 184 * 185 * @return {@code boolean} value associated with {@code key} or 186 * {@code defaultValue} if {@code key} is not valid. 187 * 188 * @throws NullPointerException if {@code key} is {@code null}. 189 */ 190 public boolean getBoolean(String key, boolean defaultValue) { 191 return idvStore.get(requireNonNull(key), defaultValue); 192 } 193 194 /** 195 * Returns the {@code double} value associated with the given {@code key}. 196 * If {@code key} does not exist, {@code defaultValue} is returned. 197 * 198 * @param key Key whose associated {@code double} value is to be returned. 199 * Cannot be {@code null}. 200 * @param defaultValue Value to be returned if {@code key} is not valid. 201 * 202 * @return {@code double} value associated with {@code key} or 203 * {@code defaultValue} if {@code key} is not valid. 204 * 205 * @throws NullPointerException if {@code key} is {@code null}. 206 */ 207 public double getDouble(String key, double defaultValue) { 208 return idvStore.get(requireNonNull(key), defaultValue); 209 } 210 211 /** 212 * Returns the {@code float} value associated with the given {@code key}. 213 * If {@code key} does not exist, {@code defaultValue} is returned. 214 * 215 * @param key Key whose associated {@code float} value is to be returned. 216 * Cannot be {@code null}. 217 * @param defaultValue Value to be returned if {@code key} is not valid. 218 * 219 * @return {@code float} value associated with {@code key} or 220 * {@code defaultValue} if {@code key} is not valid. 221 * 222 * @throws NullPointerException if {@code key} is {@code null}. 223 */ 224 public float getFloat(String key, float defaultValue) { 225 return idvStore.get(requireNonNull(key), defaultValue); 226 } 227 228 /** 229 * Returns the {@code int} value associated with the given {@code key}. 230 * If {@code key} does not exist, {@code defaultValue} is returned. 231 * 232 * @param key Key whose associated {@code int} value is to be returned. 233 * Cannot be {@code null}. 234 * @param defaultValue Value to be returned if {@code key} is not valid. 235 * 236 * @return {@code int} value associated with {@code key} or 237 * {@code defaultValue} if {@code key} is not valid. 238 * 239 * @throws NullPointerException if {@code key} is {@code null}. 240 */ 241 public int getInteger(String key, int defaultValue) { 242 return idvStore.get(requireNonNull(key), defaultValue); 243 } 244 245 /** 246 * Returns the {@code long} value associated with the given {@code key}. 247 * If {@code key} does not exist, {@code defaultValue} is returned. 248 * 249 * @param key Key whose associated {@code long} value is to be returned. 250 * Cannot be {@code null}. 251 * @param defaultValue Value to be returned if {@code key} is not valid. 252 * 253 * @return {@code long} value associated with {@code key} or 254 * {@code defaultValue} if {@code key} is not valid. 255 * 256 * @throws NullPointerException if {@code key} is {@code null}. 257 */ 258 public long getLong(String key, long defaultValue) { 259 return idvStore.get(requireNonNull(key), defaultValue); 260 } 261 262 /** 263 * Associates the given {@code key} with the given object. 264 * 265 * @param <T> Type of object to store. 266 * @param key Key to associate with the given {@code value}. 267 * Cannot be {@code null}. 268 * @param value Object to associate with {@code key}. Cannot be 269 * {@code null}. 270 * 271 * @throws NullPointerException if either {@code key} or {@code value} is 272 * {@code null}. 273 */ 274 public <T> void putObject(String key, T value) { 275 idvStore.put(requireNonNull(key), requireNonNull(value)); 276 } 277 278 /** 279 * Associates the given {@code key} with the given {@code short} value. 280 * 281 * @param key Key to associate with the given {@code value}. 282 * Cannot be {@code null}. 283 * @param value {@code short} value to associate with {@code key}. 284 * 285 * @throws NullPointerException if either {@code key} or {@code value} is 286 * {@code null}. 287 */ 288 public void putShort(String key, short value) { 289 idvStore.put(requireNonNull(key), value); 290 } 291 292 /** 293 * Associates the given {@code key} with the given {@code char} value. 294 * 295 * @param key Key to associate with the given {@code value}. 296 * Cannot be {@code null}. 297 * @param value {@code char} value to associate with {@code key}. 298 * 299 * @throws NullPointerException if either {@code key} or {@code value} is 300 * {@code null}. 301 */ 302 public void putCharacter(String key, char value) { 303 idvStore.put(requireNonNull(key), value); 304 } 305 306 /** 307 * Associates the given {@code key} with the given {@code String} value. 308 * 309 * @param key Key to associate with the given {@code value}. 310 * Cannot be {@code null}. 311 * @param value {@code String} value to associate with {@code key}. 312 * Cannot be {@code null}. 313 * 314 * @throws NullPointerException if either {@code key} or {@code value} is 315 * {@code null}. 316 */ 317 public void putString(String key, String value) { 318 idvStore.put(requireNonNull(key), requireNonNull(value)); 319 } 320 321 /** 322 * Associates the given {@code key} with the given {@code boolean} value. 323 * 324 * @param key Key to associate with the given {@code value}. 325 * Cannot be {@code null}. 326 * @param value {@code boolean} value to associate with {@code key}. 327 * 328 * @throws NullPointerException if either {@code key} or {@code value} is 329 * {@code null}. 330 */ 331 public void putBoolean(String key, boolean value) { 332 idvStore.put(requireNonNull(key), value); 333 } 334 335 /** 336 * Associates the given {@code key} with the given {@code double} value. 337 * 338 * @param key Key to associate with the given {@code value}. 339 * Cannot be {@code null}. 340 * @param value {@code double} value to associate with {@code key}. 341 * 342 * @throws NullPointerException if either {@code key} or {@code value} is 343 * {@code null}. 344 */ 345 public void putDouble(String key, double value) { 346 idvStore.put(requireNonNull(key), value); 347 } 348 349 /** 350 * Associates the given {@code key} with the given {@code float} value. 351 * 352 * @param key Key to associate with the given {@code value}. 353 * Cannot be {@code null}. 354 * @param value {@code float} value to associate with {@code key}. 355 * 356 * @throws NullPointerException if either {@code key} or {@code value} is 357 * {@code null}. 358 */ 359 public void putFloat(String key, float value) { 360 idvStore.put(requireNonNull(key), value); 361 } 362 363 /** 364 * Associates the given {@code key} with the given {@code int} value. 365 * 366 * @param key Key to associate with the given {@code value}. 367 * Cannot be {@code null}. 368 * @param value {@code int} value to associate with {@code key}. 369 * 370 * @throws NullPointerException if either {@code key} or {@code value} is 371 * {@code null}. 372 */ 373 public void putInteger(String key, int value) { 374 idvStore.put(requireNonNull(key), value); 375 } 376 377 /** 378 * Associates the given {@code key} with the given {@code long} value. 379 * 380 * @param key Key to associate with the given {@code value}. 381 * Cannot be {@code null}. 382 * @param value {@code long} value to associate with {@code key}. 383 * 384 * @throws NullPointerException if either {@code key} or {@code value} is 385 * {@code null}. 386 */ 387 public void putLong(String key, long value) { 388 idvStore.put(requireNonNull(key), value); 389 } 390 391 392 public Set<String> keys() { 393 // yeah, i don't like forwarding stuff like this either. but remember, 394 // the intent is to eventually move away from the IDV object store 395 // altogether (so this kinda redundant call may eventually go away). 396 return idvStore.getKeys(); 397 } 398 399 400 public Set<String> keys(String substring) { 401 Set<String> allKeys = idvStore.getKeys(); 402 Set<String> matches = new TreeSet<>(); 403 String lowerCase = substring.toLowerCase(); 404 for (String key : allKeys) { 405 if (key.toLowerCase().contains(lowerCase)) { 406 matches.add(key); 407 } 408 } 409 return matches; 410 } 411 412 public List<PyTuple> items() { 413 Map<String, Object> table = idvStore.getTable(); 414 List<PyTuple> l = new ArrayList<>(table.size()); 415 for (Map.Entry<String, Object> entry : table.entrySet()) { 416 l.add(new PyTuple(new PyString(entry.getKey()), Py.java2py(entry.getValue()))); 417 } 418 return l; 419 } 420 421 public List<PyTuple> items(String substring) { 422 Map<String, Object> allItems = idvStore.getTable(); 423 List<PyTuple> l = new ArrayList<>(allItems.size()); 424 String lowerCase = substring.toLowerCase(); 425 for (Map.Entry<String, Object> entry : allItems.entrySet()) { 426 String key = entry.getKey(); 427 if (key.toLowerCase().contains(lowerCase)) { 428 l.add(new PyTuple(new PyString(key), Py.java2py(entry.getValue()))); 429 430 } 431 } 432 return l; 433 } 434 435 public String listKeys() { 436 Set<String> keys = idvStore.getKeys(); 437 // 128 is just a guess as to the typical key length 438 StringBuilder s = new StringBuilder(keys.size() * 128); 439 for (String key : keys) { 440 s.append('"').append(key).append('"').append('\n'); 441 } 442 return s.toString(); 443 } 444 445 public String listMatchingKeys(String substring) { 446 Set<String> keys = idvStore.getKeys(); 447 StringBuilder s = new StringBuilder(keys.size() * 128); 448 String lowerCase = substring.toLowerCase(); 449 for (String key : keys) { 450 if (key.toLowerCase().contains(lowerCase)) { 451 s.append('"').append(key).append('"').append('\n'); 452 } 453 } 454 return s.toString(); 455 } 456 457 public String listItems() { 458 Set<String> keys = idvStore.getKeys(); 459 Map<String, Object> table = idvStore.getTable(); 460 StringBuilder s = new StringBuilder(keys.size() * 512); 461 for (String key : keys) { 462 Object value = table.get(key); 463 String type = value.getClass().getName(); 464 s.append('"').append(key).append("\", ").append(type).append(':').append(value).append('\n'); 465 } 466 return s.toString(); 467 } 468 469 public String listMatchingItems(String substring) { 470 Set<String> keys = idvStore.getKeys(); 471 Map<String, Object> table = idvStore.getTable(); 472 String lowerCase = substring.toLowerCase(); 473 StringBuilder s = new StringBuilder(keys.size() * 512); 474 for (String key : keys) { 475 if (key.toLowerCase().contains(lowerCase)) { 476 Object value = table.get(key); 477 String type = value.getClass().getName(); 478 s.append('"').append(key).append("\", ").append(type).append(':').append(value).append('\n'); 479 } 480 } 481 return s.toString(); 482 } 483}