/*
* Copyright 2009-2012 The 99 Software Foundation
*
* 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.nnsoft.guice.rocoto.variables;
import java.util.Map;
/**
* Appender which relies on another appender to provides a configuration key, and a fallback appender in case no configuration value is found.
*
* @since 6.0
*/
final class KeyAppender extends AbstractAppender
{
/** Appender which will resolve key (add the possibility for dynamic variable) */
private final Appender key;
/** Appender which will resolve default value */
private Appender defaultValue;
/** Parser to use if dynamic resolution is needed */
private Parser parser;
/**
* Constructor for key without default value.
*
* @param parser The parser from which this appender has been created.
* @param chunk
* @param key Appender to resolve configuration key.
*/
public KeyAppender( final Parser parser, final String chunk, final Appender key )
{
this(parser, chunk, key, null);
}
/**
* Constructor for key without default value.
*
* @param parser The parser from which this appender has been created.
* @param chunk
* @param key Appender to resolve configuration key.
* @param defaultValue Appender to resolve default value, may be null.
*/
public KeyAppender( final Parser parser, final String chunk, final Appender key, final Appender defaultValue )
{
super(chunk);
this.parser = parser;
this.key = key;
this.defaultValue = defaultValue;
}
/**
* {@inheritDoc}
*/
@Override
public void doAppend( StringBuilder buffer, Map<String, String> configuration, Tree<Appender> context )
{
// Resolve key eventually
StringBuilder keyBuffer = new StringBuilder();
key.append(keyBuffer, configuration, context);
String resolvedKey = keyBuffer.toString();
String resolvedValue = configuration.get(resolvedKey);
if ( resolvedValue != null )
{
// Resolved value from the configuration may have variable
// unresolved
Resolver value = parser.parse(resolvedValue);
if ( !value.needsResolving() )
{
buffer.append(resolvedValue);
}
// Process value
else
{
if ( !(value instanceof Appender) )
{
resolvedValue = value.resolve(configuration);
} else
{
StringBuilder resolvedValueBuffer = new StringBuilder();
((Appender) value).append(resolvedValueBuffer, configuration, context);
resolvedValue = resolvedValueBuffer.toString();
}
buffer.append(resolvedValue);
// Update the configuration (not necessary, but can speed up a little when complex dependency between variables)
configuration.put(resolvedKey, resolvedValue);
}
}
// No value found from configuration, take default one
else if ( defaultValue != null )
{
defaultValue.append(buffer, configuration, context);
}
// Fallback, print original chunk, will let the possibility to resolve
// it later
else
{
buffer.append(chunk);
}
}
@Override
public boolean equals( Object obj )
{
if ( obj == this )
{
return true;
}
if ( obj instanceof KeyAppender )
{
KeyAppender other = (KeyAppender) obj;
return (key != null ? key.equals(other.key) : other.key == null)
&& (defaultValue != null ? defaultValue.equals(other.defaultValue) : other.defaultValue == null);
}
return false;
}
@Override
public int hashCode()
{
return (key != null ? key.hashCode() : 0) + (defaultValue != null ? defaultValue.hashCode() * 31 : 0);
}
/**
* @return Always true
*/
public boolean needsResolving()
{
return true;
}
}