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

org.neo4j.kernel.configuration.Config Maven / Gradle / Ivy

Go to download

Neo4j kernel is a lightweight, embedded Java database designed to store data structured as graphs rather than tables. For more information, see http://neo4j.org.

There is a newer version: 5.26.0
Show newest version
/*
 * Copyright (c) 2002-2015 "Neo Technology,"
 * Network Engine for Objects in Lund AB [http://neotechnology.com]
 *
 * This file is part of Neo4j.
 *
 * Neo4j is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see .
 */
package org.neo4j.kernel.configuration;

import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CopyOnWriteArrayList;

import org.neo4j.graphdb.config.Setting;
import org.neo4j.helpers.Function;
import org.neo4j.helpers.Functions;
import org.neo4j.helpers.collection.Iterables;
import org.neo4j.kernel.impl.util.StringLogger;
import org.neo4j.kernel.info.DiagnosticsPhase;
import org.neo4j.kernel.info.DiagnosticsProvider;
import org.neo4j.kernel.logging.BufferingLogger;

import static java.lang.Character.isDigit;
import static java.util.Arrays.asList;
import static java.util.Collections.emptyList;

/**
 * This class holds the overall configuration of a Neo4j database instance. Use the accessors
 * to convert the internal key-value settings to other types.
 * 

* Users can assume that old settings have been migrated to their new counterparts, and that defaults * have been applied. *

* UI's can change configuration by calling applyChanges. Any listener, such as services that use * this configuration, can be notified of changes by implementing the {@link ConfigurationChangeListener} interface. */ public class Config implements DiagnosticsProvider { private final List listeners = new CopyOnWriteArrayList<>(); private final Map params = new ConcurrentHashMap<>( ); private final Function settingsFunction; // Messages to this log get replayed into a real logger once logging has been // instantiated. private StringLogger log = new BufferingLogger(); private Iterable> settingsClasses = emptyList(); private ConfigurationMigrator migrator; private ConfigurationValidator validator; public Config() { this( new HashMap(), Collections.>emptyList() ); } public Config( Map inputParams ) { this( inputParams, Collections.>emptyList() ); } public Config( Map inputParams, Class... settingsClasses ) { this( inputParams, asList( settingsClasses ) ); } public Config( Map inputParams, Iterable> settingsClasses ) { this.settingsFunction = Functions.map( params ); this.params.putAll( inputParams ); registerSettingsClasses( settingsClasses ); } /** Add more settings classes */ public Config registerSettingsClasses( Class ... settingsClasses ) { return registerSettingsClasses( asList(settingsClasses) ); } /** Add more settings classes. */ public Config registerSettingsClasses( Iterable> settingsClasses ) { this.settingsClasses = Iterables.concat( settingsClasses, this.settingsClasses ); this.migrator = new AnnotationBasedConfigurationMigrator( settingsClasses ); this.validator = new ConfigurationValidator( settingsClasses ); // Apply the requirements and changes the new settings classes introduce this.applyChanges( getParams() ); return this; } // TODO: Get rid of this, to allow us to have something more // elaborate as internal storage (eg. something that can keep meta data with // properties). public Map getParams() { return new HashMap<>( this.params ); } /** * Retrieve a configuration property. */ public T get( Setting setting ) { return setting.apply( settingsFunction ); } /** * Use {@link Config#applyChanges(java.util.Map)} instead, so changes are applied in * bulk and the ConfigurationChangeListeners can process the changes in one go. */ @Deprecated public Config setProperty( String key, Object value ) { // This method here is for supporting legacy server configurator api. // None should call this except external users, // as "ideally" properties should not be changed once they are loaded. this.params.put( key, value.toString() ); this.applyChanges( new HashMap<>( params ) ); return this; } /** * Replace the current set of configuration parameters with another one. */ public synchronized void applyChanges( Map newConfiguration ) { newConfiguration = migrator.apply( newConfiguration, log ); // Make sure all changes are valid validator.validate( newConfiguration ); // Figure out what changed if ( listeners.isEmpty() ) { // Make the change params.clear(); params.putAll( newConfiguration ); } else { List configurationChanges = new ArrayList<>(); for ( Map.Entry stringStringEntry : newConfiguration.entrySet() ) { String oldValue = params.get( stringStringEntry.getKey() ); String newValue = stringStringEntry.getValue(); if ( !(oldValue == null && newValue == null) && (oldValue == null || newValue == null || !oldValue.equals( newValue )) ) { configurationChanges.add( new ConfigurationChange( stringStringEntry.getKey(), oldValue, newValue ) ); } } if ( configurationChanges.isEmpty() ) { // Don't bother... nothing changed. return; } // Make the change params.clear(); for ( Map.Entry entry : newConfiguration.entrySet() ) { // Filter out nulls because we are using a ConcurrentHashMap under the covers, which doesn't support // null keys or values. String value = entry.getValue(); if ( value != null ) { params.put( entry.getKey(), value ); } } // Notify listeners for ( ConfigurationChangeListener listener : listeners ) { listener.notifyConfigurationChanges( configurationChanges ); } } } public Iterable> getSettingsClasses() { return settingsClasses; } public void setLogger( StringLogger log ) { if ( this.log instanceof BufferingLogger ) { ((BufferingLogger) this.log).replayInto( log ); } this.log = log; } public void addConfigurationChangeListener( ConfigurationChangeListener listener ) { listeners.add( listener ); } public void removeConfigurationChangeListener( ConfigurationChangeListener listener ) { listeners.remove( listener ); } @Override public String getDiagnosticsIdentifier() { return getClass().getName(); } @Override public void acceptDiagnosticsVisitor( Object visitor ) { // nothing visits configuration } @Override public void dump( DiagnosticsPhase phase, StringLogger log ) { if ( phase.isInitialization() || phase.isExplicitlyRequested() ) { log.logLongMessage( "Neo4j Kernel properties:", Iterables.map( new Function, String>() { @Override public String apply( Map.Entry stringStringEntry ) { return stringStringEntry.getKey() + "=" + stringStringEntry.getValue(); } }, params.entrySet() ) ); } } @Override public String toString() { List keys = new ArrayList<>( params.keySet() ); Collections.sort( keys ); LinkedHashMap output = new LinkedHashMap<>(); for ( String key : keys ) { output.put( key, params.get( key ) ); } return output.toString(); } public static long parseLongWithUnit( String numberWithPotentialUnit ) { int firstNonDigitIndex = findFirstNonDigit( numberWithPotentialUnit ); String number = numberWithPotentialUnit.substring( 0, firstNonDigitIndex ); long multiplier = 1; if ( firstNonDigitIndex < numberWithPotentialUnit.length() ) { String unit = numberWithPotentialUnit.substring( firstNonDigitIndex ); if ( unit.equalsIgnoreCase( "k" ) ) { multiplier = 1024; } else if ( unit.equalsIgnoreCase( "m" ) ) { multiplier = 1024 * 1024; } else if ( unit.equalsIgnoreCase( "g" ) ) { multiplier = 1024 * 1024 * 1024; } else { throw new IllegalArgumentException( "Illegal unit '" + unit + "' for number '" + numberWithPotentialUnit + "'" ); } } return Long.parseLong( number ) * multiplier; } /** * @return index of first non-digit character in {@code numberWithPotentialUnit}. If all digits then * {@code numberWithPotentialUnit.length()} is returned. */ private static int findFirstNonDigit( String numberWithPotentialUnit ) { int firstNonDigitIndex = numberWithPotentialUnit.length(); for ( int i = 0; i < numberWithPotentialUnit.length(); i++ ) { if ( !isDigit( numberWithPotentialUnit.charAt( i ) ) ) { firstNonDigitIndex = i; break; } } return firstNonDigitIndex; } /** * Returns a copy of this config with the given modifications. * @return a new modified config, leaves this config unchanged. */ public Config with( Map additionalConfig ) { Map newParams = getParams(); // copy is returned newParams.putAll( additionalConfig ); return new Config( newParams ); } }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy