All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.pentaho.di.core.ConcurrentMapProperties Maven / Gradle / Ivy

The newest version!
/*******************************************************************************
 *
 * Pentaho Data Integration
 *
 * Copyright (C) 2002-2018 by Hitachi Vantara : http://www.pentaho.com
 *
 *******************************************************************************
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with
 * the License. You may obtain a copy of the License at
 *
 *    http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 ******************************************************************************/
package org.pentaho.di.core;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.PrintStream;
import java.io.PrintWriter;
import java.io.Reader;
import java.io.Writer;
import java.util.Collection;
import java.util.Enumeration;
import java.util.HashSet;
import java.util.InvalidPropertiesFormatException;
import java.util.Map;
import java.util.Properties;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.function.BiConsumer;
import java.util.function.BiFunction;
import java.util.function.Function;

import org.apache.commons.collections.IteratorUtils;

/**
 * Thread Safe version of Java Properties class.
 */
public class ConcurrentMapProperties extends Properties {

  private static final long serialVersionUID = -7444528393201025496L;

  protected ConcurrentMap storageMap = new ConcurrentHashMap<>();

  public ConcurrentMapProperties() {
    this( null );
  }

  public ConcurrentMapProperties( Properties defaults ) {
    if ( defaults != null ) {
      if ( defaults instanceof ConcurrentMapProperties ) {
        this.defaults = defaults;
      } else {
        this.defaults = convertProperties( defaults );
      }
    }
  }

  @Override
  public synchronized Object put( Object key, Object value ) {
    return storageMap.put( key, value );
  }

  @Override
  public synchronized Object remove( Object key ) {
    return storageMap.remove( key );
  }

  @Override
  public synchronized void clear() {
    storageMap.clear();
  }

  @Override
  public synchronized Object clone() {
    ConcurrentMapProperties cloned = new ConcurrentMapProperties();
    cloned.putAll( storageMap );
    return cloned;
  }

  @Override
  public boolean containsValue( Object value ) {
    return storageMap.containsValue( value );
  }

  @Override
  public synchronized Object get( Object key ) {
    return storageMap.get( key );
  }

  @Override
  public synchronized Object compute( Object key,
                                      BiFunction remappingFunction ) {
    return storageMap.compute( key, remappingFunction );
  }

  @Override
  public synchronized Object computeIfAbsent( Object key, Function mappingFunction ) {
    return storageMap.computeIfAbsent( key, mappingFunction );
  }

  @Override
  public synchronized Object computeIfPresent( Object key,
                                               BiFunction
                                                 remappingFunction ) {
    return storageMap.computeIfPresent( key, remappingFunction );
  }

  @Override
  public synchronized boolean contains( Object value ) {
    return storageMap.containsValue( value );
  }

  @Override
  public synchronized boolean isEmpty() {
    return storageMap.isEmpty();
  }

  @Override
  public synchronized int size() {
    return storageMap.size();
  }

  @Override
  public synchronized boolean containsKey( Object key ) {
    return storageMap.containsKey( key );
  }

  @SuppressWarnings( "unchecked" )
  @Override
  public synchronized Enumeration elements() {
    return (Enumeration) IteratorUtils.asEnumeration( storageMap.values().iterator() );
  }

  @Override
  public Set> entrySet() {
    return storageMap.entrySet();
  }

  @Override
  public synchronized void forEach( BiConsumer action ) {
    storageMap.forEach( action );
  }

  @Override
  public synchronized Object getOrDefault( Object key, Object defaultValue ) {
    return storageMap.getOrDefault( key, defaultValue );
  }

  @SuppressWarnings( "unchecked" )
  @Override
  public synchronized Enumeration keys() {
    return (Enumeration) IteratorUtils.asEnumeration( storageMap.keySet().iterator() );
  }

  @Override
  public Set keySet() {
    return storageMap.keySet();
  }

  @Override
  public synchronized Object merge( Object key, Object value,
                                    BiFunction remappingFunction ) {
    return storageMap.merge( key, value, remappingFunction );
  }

  @Override
  public synchronized void putAll( Map t ) {
    storageMap.putAll( t );
  }

  @Override
  public synchronized Object putIfAbsent( Object key, Object value ) {
    return storageMap.putIfAbsent( key, value );
  }

  @Override
  public synchronized boolean remove( Object key, Object value ) {
    return storageMap.remove( key, value );
  }

  @Override
  public synchronized boolean replace( Object key, Object oldValue, Object newValue ) {
    return storageMap.replace( key, oldValue, newValue );
  }

  @Override
  public synchronized void replaceAll( BiFunction function ) {
    storageMap.replaceAll( function );
  }

  @Override
  public synchronized Object replace( Object key, Object value ) {
    return storageMap.replace( key, value );
  }

  @Override
  public Collection values() {
    return storageMap.values();
  }

  @Override
  public String getProperty( String key ) {
    Object oval = storageMap.get( key );
    String sval = ( oval instanceof String ) ? (String) oval : null;
    return ( ( sval == null ) && ( defaults != null ) ) ? defaults.getProperty( key ) : sval;
  }

  @Override
  public String getProperty( String key, String defaultValue ) {
    /*
     * This method simply uses getProperty(String key), so it is fine to use the original implementation
     */
    return super.getProperty( key, defaultValue );
  }

  @Override
  public synchronized Object setProperty( String key, String value ) {
    return storageMap.put( key, value );
  }

  @Override
  public synchronized boolean equals( Object o ) {
    super.putAll( storageMap );
    boolean result = super.equals( o );
    super.clear();
    return result;
  }

  @Override
  public synchronized String toString() {
    super.putAll( storageMap );
    String result = super.toString();
    super.clear();
    return result;
  }

  @Override
  public synchronized int hashCode() {
    super.putAll( storageMap );
    int result = super.hashCode();
    super.clear();
    return result;
  }

  @Override
  public synchronized Enumeration propertyNames() {
    return IteratorUtils.asEnumeration( stringPropertyNames().iterator() );
  }

  @Override
  public synchronized Set stringPropertyNames() {
    Set copiedSet = new HashSet<>();
    if ( defaults != null ) {
      defaults.keySet().forEach( x -> copiedSet.add( (String) x ) );
    }
    storageMap.keySet().forEach( x -> copiedSet.add( (String) x ) );
    return copiedSet;
  }

  @Override
  public synchronized void list( PrintStream out ) {
    super.putAll( storageMap );
    super.list( out );
    super.clear();
  }

  @Override
  public synchronized void list( PrintWriter out ) {
    super.putAll( storageMap );
    super.list( out );
    super.clear();
  }

  @Override
  public synchronized void load( InputStream inStream ) throws IOException {
    super.putAll( storageMap );
    super.load( inStream );
    super.forEach( ( key, value ) -> storageMap.put( key, value ) );
    super.clear();
  }

  @Override
  public synchronized void load( Reader reader ) throws IOException {
    super.putAll( storageMap );
    super.load( reader );
    super.forEach( ( key, value ) -> storageMap.put( key, value ) );
    super.clear();
  }

  @Override
  public synchronized void loadFromXML( InputStream in ) throws IOException, InvalidPropertiesFormatException {
    super.putAll( storageMap );
    super.loadFromXML( in );
    super.forEach( ( key, value ) -> storageMap.putIfAbsent( key, value ) );
    super.clear();
  }

  @Override
  @Deprecated
  public synchronized void save( OutputStream out, String comments ) {
    super.putAll( storageMap );
    super.save( out, comments );
    super.clear();
  }

  @Override
  public synchronized void store( OutputStream out, String comments ) throws IOException {
    super.putAll( storageMap );
    super.store( out, comments );
    super.clear();
  }

  @Override
  public synchronized void store( Writer writer, String comments ) throws IOException {
    super.putAll( storageMap );
    super.store( writer, comments );
    super.clear();
  }

  @Override
  public synchronized void storeToXML( OutputStream os, String comment ) throws IOException {
    super.putAll( storageMap );
    super.storeToXML( os, comment );
    super.clear();
  }

  @Override
  public synchronized void storeToXML( OutputStream os, String comment, String encoding ) throws IOException {
    super.putAll( storageMap );
    super.storeToXML( os, comment, encoding );
    super.clear();
  }

  /**
   * Converts a Properties object to a ConcurrentMapProperties object
   *
   * @param props
   * @return A new ConcurrentMapProperties with all properties enumerated (including defaults)
   */
  public static ConcurrentMapProperties convertProperties( Properties props ) {
    if ( props != null ) {
      if ( !( props instanceof ConcurrentMapProperties ) ) {
        ConcurrentMapProperties result = new ConcurrentMapProperties( null );
        synchronized ( props ) {
          for ( String prop : props.stringPropertyNames() ) {
            result.put( prop, props.getProperty( prop ) );
          }
        }
        return result;
      } else {
        //Already a ConcurrentMapProperties
        return (ConcurrentMapProperties) props;
      }
    }
    return null;
  }

}