001/* 002 * This file is part of McIDAS-V 003 * 004 * Copyright 2007-2015 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 key Key whose associated object is to be returned. 108 * Cannot be {@code null}. 109 * @param defaultValue Value to be returned if {@code key} is not valid. 110 * {@code null} is allowed. 111 * 112 * @return Object associated with {@code key} or {@code defaultValue} if 113 * {@code key} is not valid. 114 * 115 * @throws NullPointerException if {@code key} is {@code null}. 116 */ 117 public <T> T getObject(String key, T defaultValue) { 118 T storedValue = (T)idvStore.get(requireNonNull(key)); 119 if (storedValue == null) { 120 storedValue = defaultValue; 121 } 122 return storedValue; 123 } 124 125 /** 126 * Returns the {@code short} value associated with the given {@code key}. 127 * If {@code key} does not exist, {@code defaultValue} is returned. 128 * 129 * @param key Key whose associated {@code short} value is to be returned. 130 * Cannot be {@code null}. 131 * @param defaultValue Value to be returned if {@code key} is not valid. 132 * 133 * @return {@code short} value associated with {@code key} or 134 * {@code defaultValue} if {@code key} is not valid. 135 * 136 * @throws NullPointerException if {@code key} is {@code null}. 137 */ 138 public short getShort(String key, short defaultValue) { 139 return idvStore.get(requireNonNull(key), defaultValue); 140 } 141 142 /** 143 * Returns the {@code char} value associated with the given {@code key}. 144 * If {@code key} does not exist, {@code defaultValue} is returned. 145 * 146 * @param key Key whose associated {@code char} value is to be returned. 147 * Cannot be {@code null}. 148 * @param defaultValue Value to be returned if {@code key} is not valid. 149 * 150 * @return {@code char} value associated with {@code key} or 151 * {@code defaultValue} if {@code key} is not valid. 152 * 153 * @throws NullPointerException if {@code key} is {@code null}. 154 */ 155 public char getCharacter(String key, char defaultValue) { 156 return idvStore.get(requireNonNull(key), defaultValue); 157 } 158 159 /** 160 * Returns the {@code String} value associated with the given {@code key}. 161 * If {@code key} does not exist, {@code defaultValue} is returned. 162 * 163 * @param key Key whose associated {@code String} value is to be returned. 164 * Cannot be {@code null}. 165 * @param defaultValue Value to be returned if {@code key} is not valid. 166 * 167 * @return {@code String} value associated with {@code key} or 168 * {@code defaultValue} if {@code key} is not valid. 169 * 170 * @throws NullPointerException if {@code key} is {@code null}. 171 */ 172 public String getString(String key, String defaultValue) { 173 return idvStore.get(requireNonNull(key), defaultValue); 174 } 175 176 /** 177 * Returns the {@code boolean} value associated with the given {@code key}. 178 * If {@code key} does not exist, {@code defaultValue} is returned. 179 * 180 * @param key Key whose associated {@code boolean} value is to be returned. 181 * Cannot be {@code null}. 182 * @param defaultValue Value to be returned if {@code key} is not valid. 183 * 184 * @return {@code boolean} value associated with {@code key} or 185 * {@code defaultValue} if {@code key} is not valid. 186 * 187 * @throws NullPointerException if {@code key} is {@code null}. 188 */ 189 public boolean getBoolean(String key, boolean defaultValue) { 190 return idvStore.get(requireNonNull(key), defaultValue); 191 } 192 193 /** 194 * Returns the {@code double} value associated with the given {@code key}. 195 * If {@code key} does not exist, {@code defaultValue} is returned. 196 * 197 * @param key Key whose associated {@code double} value is to be returned. 198 * Cannot be {@code null}. 199 * @param defaultValue Value to be returned if {@code key} is not valid. 200 * 201 * @return {@code double} value associated with {@code key} or 202 * {@code defaultValue} if {@code key} is not valid. 203 * 204 * @throws NullPointerException if {@code key} is {@code null}. 205 */ 206 public double getDouble(String key, double defaultValue) { 207 return idvStore.get(requireNonNull(key), defaultValue); 208 } 209 210 /** 211 * Returns the {@code float} value associated with the given {@code key}. 212 * If {@code key} does not exist, {@code defaultValue} is returned. 213 * 214 * @param key Key whose associated {@code float} value is to be returned. 215 * Cannot be {@code null}. 216 * @param defaultValue Value to be returned if {@code key} is not valid. 217 * 218 * @return {@code float} value associated with {@code key} or 219 * {@code defaultValue} if {@code key} is not valid. 220 * 221 * @throws NullPointerException if {@code key} is {@code null}. 222 */ 223 public float getFloat(String key, float defaultValue) { 224 return idvStore.get(requireNonNull(key), defaultValue); 225 } 226 227 /** 228 * Returns the {@code int} value associated with the given {@code key}. 229 * If {@code key} does not exist, {@code defaultValue} is returned. 230 * 231 * @param key Key whose associated {@code int} value is to be returned. 232 * Cannot be {@code null}. 233 * @param defaultValue Value to be returned if {@code key} is not valid. 234 * 235 * @return {@code int} value associated with {@code key} or 236 * {@code defaultValue} if {@code key} is not valid. 237 * 238 * @throws NullPointerException if {@code key} is {@code null}. 239 */ 240 public int getInteger(String key, int defaultValue) { 241 return idvStore.get(requireNonNull(key), defaultValue); 242 } 243 244 /** 245 * Returns the {@code long} value associated with the given {@code key}. 246 * If {@code key} does not exist, {@code defaultValue} is returned. 247 * 248 * @param key Key whose associated {@code long} value is to be returned. 249 * Cannot be {@code null}. 250 * @param defaultValue Value to be returned if {@code key} is not valid. 251 * 252 * @return {@code long} value associated with {@code key} or 253 * {@code defaultValue} if {@code key} is not valid. 254 * 255 * @throws NullPointerException if {@code key} is {@code null}. 256 */ 257 public long getLong(String key, long defaultValue) { 258 return idvStore.get(requireNonNull(key), defaultValue); 259 } 260 261 /** 262 * Associates the given {@code key} with the given object. 263 * 264 * @param key Key to associate with the given {@code value}. 265 * Cannot be {@code null}. 266 * @param value Object to associate with {@code key}. Cannot be 267 * {@code null}. 268 * 269 * @throws NullPointerException if either {@code key} or {@code value} is 270 * {@code null}. 271 */ 272 public <T> void putObject(String key, T value) { 273 idvStore.put(requireNonNull(key), requireNonNull(value)); 274 } 275 276 /** 277 * Associates the given {@code key} with the given {@code short} value. 278 * 279 * @param key Key to associate with the given {@code value}. 280 * Cannot be {@code null}. 281 * @param value {@code short} value to associate with {@code key}. 282 * 283 * @throws NullPointerException if either {@code key} or {@code value} is 284 * {@code null}. 285 */ 286 public void putShort(String key, short value) { 287 idvStore.put(requireNonNull(key), value); 288 } 289 290 /** 291 * Associates the given {@code key} with the given {@code char} value. 292 * 293 * @param key Key to associate with the given {@code value}. 294 * Cannot be {@code null}. 295 * @param value {@code char} value to associate with {@code key}. 296 * 297 * @throws NullPointerException if either {@code key} or {@code value} is 298 * {@code null}. 299 */ 300 public void putCharacter(String key, char value) { 301 idvStore.put(requireNonNull(key), value); 302 } 303 304 /** 305 * Associates the given {@code key} with the given {@code String} value. 306 * 307 * @param key Key to associate with the given {@code value}. 308 * Cannot be {@code null}. 309 * @param value {@code String} value to associate with {@code key}. 310 * Cannot be {@code null}. 311 * 312 * @throws NullPointerException if either {@code key} or {@code value} is 313 * {@code null}. 314 */ 315 public void putString(String key, String value) { 316 idvStore.put(requireNonNull(key), requireNonNull(value)); 317 } 318 319 /** 320 * Associates the given {@code key} with the given {@code boolean} value. 321 * 322 * @param key Key to associate with the given {@code value}. 323 * Cannot be {@code null}. 324 * @param value {@code boolean} value to associate with {@code key}. 325 * 326 * @throws NullPointerException if either {@code key} or {@code value} is 327 * {@code null}. 328 */ 329 public void putBoolean(String key, boolean value) { 330 idvStore.put(requireNonNull(key), value); 331 } 332 333 /** 334 * Associates the given {@code key} with the given {@code double} value. 335 * 336 * @param key Key to associate with the given {@code value}. 337 * Cannot be {@code null}. 338 * @param value {@code double} value to associate with {@code key}. 339 * 340 * @throws NullPointerException if either {@code key} or {@code value} is 341 * {@code null}. 342 */ 343 public void putDouble(String key, double value) { 344 idvStore.put(requireNonNull(key), value); 345 } 346 347 /** 348 * Associates the given {@code key} with the given {@code float} value. 349 * 350 * @param key Key to associate with the given {@code value}. 351 * Cannot be {@code null}. 352 * @param value {@code float} value to associate with {@code key}. 353 * 354 * @throws NullPointerException if either {@code key} or {@code value} is 355 * {@code null}. 356 */ 357 public void putFloat(String key, float value) { 358 idvStore.put(requireNonNull(key), value); 359 } 360 361 /** 362 * Associates the given {@code key} with the given {@code int} value. 363 * 364 * @param key Key to associate with the given {@code value}. 365 * Cannot be {@code null}. 366 * @param value {@code int} value to associate with {@code key}. 367 * 368 * @throws NullPointerException if either {@code key} or {@code value} is 369 * {@code null}. 370 */ 371 public void putInteger(String key, int value) { 372 idvStore.put(requireNonNull(key), value); 373 } 374 375 /** 376 * Associates the given {@code key} with the given {@code long} value. 377 * 378 * @param key Key to associate with the given {@code value}. 379 * Cannot be {@code null}. 380 * @param value {@code long} value to associate with {@code key}. 381 * 382 * @throws NullPointerException if either {@code key} or {@code value} is 383 * {@code null}. 384 */ 385 public void putLong(String key, long value) { 386 idvStore.put(requireNonNull(key), value); 387 } 388 389 390 public Set<String> keys() { 391 // yeah, i don't like forwarding stuff like this either. but remember, 392 // the intent is to eventually move away from the IDV object store 393 // altogether (so this kinda redundant call may eventually go away). 394 return idvStore.getKeys(); 395 } 396 397 398 public Set<String> keys(String substring) { 399 Set<String> allKeys = idvStore.getKeys(); 400 Set<String> matches = new TreeSet<>(); 401 String lowerCase = substring.toLowerCase(); 402 for (String key : allKeys) { 403 if (key.toLowerCase().contains(lowerCase)) { 404 matches.add(key); 405 } 406 } 407 return matches; 408 } 409 410 public List<PyTuple> items() { 411 Map<String, Object> table = idvStore.getTable(); 412 List<PyTuple> l = new ArrayList<>(table.size()); 413 for (Map.Entry<String, Object> entry : table.entrySet()) { 414 l.add(new PyTuple(new PyString(entry.getKey()), Py.java2py(entry.getValue()))); 415 } 416 return l; 417 } 418 419 public List<PyTuple> items(String substring) { 420 Map<String, Object> allItems = idvStore.getTable(); 421 List<PyTuple> l = new ArrayList<>(allItems.size()); 422 String lowerCase = substring.toLowerCase(); 423 for (Map.Entry<String, Object> entry : allItems.entrySet()) { 424 String key = entry.getKey(); 425 if (key.toLowerCase().contains(lowerCase)) { 426 l.add(new PyTuple(new PyString(key), Py.java2py(entry.getValue()))); 427 428 } 429 } 430 return l; 431 } 432 433 public String listKeys() { 434 Set<String> keys = idvStore.getKeys(); 435 // 128 is just a guess as to the typical key length 436 StringBuilder s = new StringBuilder(keys.size() * 128); 437 for (String key : keys) { 438 s.append('"').append(key).append('"').append('\n'); 439 } 440 return s.toString(); 441 } 442 443 public String listMatchingKeys(String substring) { 444 Set<String> keys = idvStore.getKeys(); 445 StringBuilder s = new StringBuilder(keys.size() * 128); 446 String lowerCase = substring.toLowerCase(); 447 for (String key : keys) { 448 if (key.toLowerCase().contains(lowerCase)) { 449 s.append('"').append(key).append('"').append('\n'); 450 } 451 } 452 return s.toString(); 453 } 454 455 public String listItems() { 456 Set<String> keys = idvStore.getKeys(); 457 Map<String, Object> table = idvStore.getTable(); 458 StringBuilder s = new StringBuilder(keys.size() * 512); 459 for (String key : keys) { 460 Object value = table.get(key); 461 String type = value.getClass().getName(); 462 s.append('"').append(key).append("\", ").append(type).append(':').append(value).append('\n'); 463 } 464 return s.toString(); 465 } 466 467 public String listMatchingItems(String substring) { 468 Set<String> keys = idvStore.getKeys(); 469 Map<String, Object> table = idvStore.getTable(); 470 String lowerCase = substring.toLowerCase(); 471 StringBuilder s = new StringBuilder(keys.size() * 512); 472 for (String key : keys) { 473 if (key.toLowerCase().contains(lowerCase)) { 474 Object value = table.get(key); 475 String type = value.getClass().getName(); 476 s.append('"').append(key).append("\", ").append(type).append(':').append(value).append('\n'); 477 } 478 } 479 return s.toString(); 480 } 481}