com.mchange.v2.cfg.ConfigUtils Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of org.apache.servicemix.bundles.mchange-commons-java
Show all versions of org.apache.servicemix.bundles.mchange-commons-java
This OSGi bundle wraps ${pkgArtifactId} ${pkgVersion} jar file.
The newest version!
/*
* Distributed as part of mchange-commons-java 0.2.11
*
* Copyright (C) 2015 Machinery For Change, Inc.
*
* Author: Steve Waldman
*
* This library is free software; you can redistribute it and/or modify
* it under the terms of EITHER:
*
* 1) The GNU Lesser General Public License (LGPL), version 2.1, as
* published by the Free Software Foundation
*
* OR
*
* 2) The Eclipse Public License (EPL), version 1.0
*
* You may choose which license to accept if you wish to redistribute
* or modify this work. You may offer derivatives of this work
* under the license you have chosen, or you may provide the same
* choice of license which you have been offered here.
*
* This software 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.
*
* You should have received copies of both LGPL v2.1 and EPL v1.0
* along with this software; see the files LICENSE-EPL and LICENSE-LGPL.
* If not, the text of these licenses are currently available at
*
* LGPL v2.1: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html
* EPL v1.0: http://www.eclipse.org/org/documents/epl-v10.php
*
*/
package com.mchange.v2.cfg;
import java.util.*;
import java.io.*;
import static com.mchange.v2.cfg.DelayedLogItem.*;
// external clients should go through the MConfig facade.
final class ConfigUtils
{
private final static String[] DFLT_VM_RSRC_PATHFILES = new String[] {"/com/mchange/v2/cfg/vmConfigResourcePaths.txt", "/mchange-config-resource-paths.txt"};
private final static String[] HARDCODED_DFLT_RSRC_PATHS = new String[]
{
"/mchange-commons.properties",
"hocon:/reference,/application,/",
"/"
};
final static String[] NO_PATHS = new String[0];
//MT: protected by class' lock
static MultiPropertiesConfig vmConfig = null;
//public static MultiPropertiesConfig read(String[] resourcePath, MLogger logger)
//{ return new BasicMultiPropertiesConfig( resourcePath, logger ); }
static MultiPropertiesConfig read(String[] resourcePath, List delayedLogItems)
{ return new BasicMultiPropertiesConfig( resourcePath, delayedLogItems ); }
public static MultiPropertiesConfig read(String[] resourcePath)
{ return new BasicMultiPropertiesConfig( resourcePath ); }
/**
* Later entries in the configs array override earlier entries.
*/
public static MultiPropertiesConfig combine( MultiPropertiesConfig[] configs )
{ return new CombinedMultiPropertiesConfig( configs ).toBasic(); }
public static MultiPropertiesConfig readVmConfig(String[] defaultResources, String[] preemptingResources )
{ return readVmConfig( defaultResources, preemptingResources, (List) null ); }
/*
public static MultiPropertiesConfig readVmConfig(String[] defaultResources, String[] preemptingResources, MLogger logger)
{
List items = new ArrayList();
MultiPropertiesConfig out = readVmConfig( defaultResources, preemptingResources, items );
items.addAll( out.getDelayedLogItems() );
for (Iterator ii = items.iterator(); ii.hasNext(); )
{
DelayedLogItem item = (DelayedLogItem) ii.next();
logger.log( item.getLevel(), item.getText(), item.getException() );
}
return out;
}
*/
static List vmCondensedPaths(String[] defaultResources, String[] preemptingResources, List delayedLogItemsOut)
{
List raw = condensePaths( new String[][]{ defaultResources, vmResourcePaths( delayedLogItemsOut ), preemptingResources } );
return ensureHoconInterresolvability( raw );
}
static String stringFromPathsList( List pathsList )
{
StringBuffer sb = new StringBuffer(2048);
for ( int i = 0, len = pathsList.size(); i < len; ++i)
{
if ( i != 0 ) sb.append(", ");
sb.append( pathsList.get(i) );
}
return sb.toString();
}
public static MultiPropertiesConfig readVmConfig(String[] defaultResources, String[] preemptingResources, List delayedLogItemsOut)
{
defaultResources = ( defaultResources == null ? NO_PATHS : defaultResources );
preemptingResources = ( preemptingResources == null ? NO_PATHS : preemptingResources );
List pathsList = vmCondensedPaths( defaultResources, preemptingResources, delayedLogItemsOut );
if ( delayedLogItemsOut != null )
delayedLogItemsOut.add( new DelayedLogItem(Level.FINER, "Reading VM config for path list " + stringFromPathsList( pathsList ) ) );
return read( (String[]) pathsList.toArray(new String[pathsList.size()]), delayedLogItemsOut );
}
private static List condensePaths(String[][] pathLists)
{
// we do this in reverse, so that the "first" time
// we encounter a path becomes the last in the resultant
// list. that is, we want redundantly specified paths
// to have their maximum specified preference
Set pathSet = new HashSet();
List reverseMe = new ArrayList();
for ( int i = pathLists.length; --i >= 0; )
for( int j = pathLists[i].length; --j >= 0; )
{
String path = pathLists[i][j];
if (! pathSet.contains( path ) )
{
pathSet.add( path );
reverseMe.add( path );
}
}
Collections.reverse( reverseMe );
return reverseMe;
}
private static List readResourcePathsFromResourcePathsTextFile( String resourcePathsTextFileResourcePath, List delayedLogItemsOut )
{
List rps = new ArrayList();
BufferedReader br = null;
try
{
InputStream is = MultiPropertiesConfig.class.getResourceAsStream( resourcePathsTextFileResourcePath );
if ( is != null )
{
br = new BufferedReader( new InputStreamReader( is, "8859_1" ) );
String rp;
while ((rp = br.readLine()) != null)
{
rp = rp.trim();
if ("".equals( rp ) || rp.startsWith("#"))
continue;
rps.add( rp );
}
if ( delayedLogItemsOut != null )
delayedLogItemsOut.add( new DelayedLogItem( Level.FINEST, String.format( "Added paths from resource path text file at '%s'", resourcePathsTextFileResourcePath ) ) );
}
else if ( delayedLogItemsOut != null )
delayedLogItemsOut.add( new DelayedLogItem( Level.FINEST, String.format( "Could not find resource path text file for path '%s'. Skipping.", resourcePathsTextFileResourcePath ) ) );
}
catch (IOException e)
{ e.printStackTrace(); }
finally
{
try { if ( br != null ) br.close(); }
catch (IOException e) { e.printStackTrace(); }
}
return rps;
}
private static List readResourcePathsFromResourcePathsTextFiles( String[] resourcePathsTextFileResourcePaths, List delayedLogItemsOut )
{
List out = new ArrayList();
for ( int i = 0, len = resourcePathsTextFileResourcePaths.length; i < len; ++i )
out.addAll( readResourcePathsFromResourcePathsTextFile( resourcePathsTextFileResourcePaths[i], delayedLogItemsOut ) );
return out;
}
private static String[] vmResourcePaths( List delayedLogItemsOut )
{
List paths = vmResourcePathList( delayedLogItemsOut );
return (String[]) paths.toArray( new String[ paths.size() ] );
}
private static List vmResourcePathList( List delayedLogItemsOut )
{
List pathsFromFiles = readResourcePathsFromResourcePathsTextFiles( DFLT_VM_RSRC_PATHFILES, delayedLogItemsOut );
List rps;
if ( pathsFromFiles.size() > 0 )
rps = pathsFromFiles;
else
rps = Arrays.asList( HARDCODED_DFLT_RSRC_PATHS );
return rps;
}
public synchronized static MultiPropertiesConfig readVmConfig()
{ return readVmConfig( (List) null ); }
/*
public synchronized static MultiPropertiesConfig readVmConfig( MLogger logger )
{
List items = new ArrayList();
MultiPropertiesConfig out = readVmConfig( items );
items.addAll( out.getDelayedLogItems() );
for (Iterator ii = items.iterator(); ii.hasNext(); )
{
DelayedLogItem item = (DelayedLogItem) ii.next();
logger.log( item.getLevel(), item.getText(), item.getException() );
}
return out;
}
*/
public synchronized static MultiPropertiesConfig readVmConfig( List delayedLogItemsOut )
{
if ( vmConfig == null )
{
List rps = vmResourcePathList( delayedLogItemsOut );
vmConfig = new BasicMultiPropertiesConfig( (String[]) rps.toArray( new String[ rps.size() ] ) );
}
return vmConfig;
}
public static synchronized boolean foundVmConfig()
{ return vmConfig != null; }
public static void dumpByPrefix( MultiPropertiesConfig mpc, String pfx )
{
Properties props = mpc.getPropertiesByPrefix(pfx);
Map m = new TreeMap();
m.putAll( props );
for ( Iterator ii = m.entrySet().iterator(); ii.hasNext(); )
{
Map.Entry entry = (Map.Entry) ii.next();
System.err.println( entry.getKey() + " --> " + entry.getValue() );
}
}
private static void putToSet(Map> map, String key, String value ) {
Set set = map.get( key );
if ( set == null ) {
set = new HashSet();
map.put( key, set );
}
set.add( value );
}
private static String makeHoconPathFromElements( List newElementsList ) {
StringBuilder sb = new StringBuilder();
sb.append("hocon:");
boolean first = true;
for( String element : newElementsList ) {
if ( first ) first = false;
else sb.append(",");
sb.append( element );
}
return sb.toString();
}
private static String normalizeHoconPathElement( String element ) {
return ( element.indexOf(":") < 0 && element.charAt(0) != '/' ) ? ('/' + element) : element;
}
/*
* Well, this is a pain.
*
* The issue is that multiple applications can set up mutiple HOCON overlapping paths,
* and users, expecting the resolution associated with one application's ful HOCON path,
* can define substitutions that can't be fulfilled in a different application's config path.
*
* Our solution is to detect HOCON paths that overlap, and let overlapping paths fall back
* to one another in an ordering preserving way, so that most-recent HOCON paths always win,
* and within individual HOCON paths, the explicit specification overrides, but other overlapping
* specifications are available behind the explicit specification, in the same ordering as their
* paths are specified for the VM
*/
private static List ensureHoconInterresolvability( List paths ) {
Map> hoconPathToElementsList = new HashMap>();
Map> elementToHoconPaths = new HashMap>();
List out = new ArrayList();
// pass 1
for ( String path : paths ) {
if (path.toLowerCase().startsWith("hocon:")) {
String[] elements = path.substring("hocon:".length()).split("\\s*,\\s*");
for ( int i = 0, len = elements.length; i < len; ++i )
elements[i] = normalizeHoconPathElement( elements[i] );
hoconPathToElementsList.put( path, Arrays.asList( elements ) );
for (String element : elements ) {
putToSet(elementToHoconPaths, element, path );
if ( element.indexOf('.') < 0 && !"/".equals( element ) ) {
putToSet( elementToHoconPaths, element + ".conf", path );
putToSet( elementToHoconPaths, element + ".properties", path );
putToSet( elementToHoconPaths, element + ".json", path );
}
}
}
}
// pass 2
for ( String path : paths ) {
if (path.toLowerCase().startsWith("hocon:")) {
List elements = hoconPathToElementsList.get( path );
Set pathSet = new HashSet();
for( String element : elements ) {
// don't let mutual use of system properties constitute overlap,
// since system properties can't contain resolvable substitutions
if ( !"/".equals( element ) ) pathSet.addAll( elementToHoconPaths.get( element ) );
}
List newElementsList = new ArrayList();
for( String orderSettingPath : paths ) {
if (path.toLowerCase().startsWith("hocon:")) {
if ( orderSettingPath != path ) { // we add the current path's elements last, since last override
if ( pathSet.contains( orderSettingPath ) ) {
newElementsList.addAll( hoconPathToElementsList.get( orderSettingPath ) );
}
}
}
}
newElementsList.addAll( hoconPathToElementsList.get( path ) );
out.add( makeHoconPathFromElements( newElementsList ) );
} else {
out.add( path );
}
}
return out;
}
private ConfigUtils()
{}
}