tech.sirwellington.alchemy.arguments.AssertionBuilderImpl Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of alchemy-arguments Show documentation
Show all versions of alchemy-arguments Show documentation
Part of the Alchemy Collection.
Easy, Simple, and Robust argument checking logic
for your Services, Libraries, and Scripts.
/*
* Copyright 2015 SirWellington Tech.
*
* 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 tech.sirwellington.alchemy.arguments;
import java.util.List;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import tech.sirwellington.alchemy.annotations.access.Internal;
import tech.sirwellington.alchemy.annotations.concurrency.Immutable;
import tech.sirwellington.alchemy.annotations.designs.FluidAPIDesign;
import tech.sirwellington.alchemy.annotations.designs.patterns.StrategyPattern;
import static tech.sirwellington.alchemy.annotations.designs.patterns.StrategyPattern.Role.CLIENT;
import static tech.sirwellington.alchemy.arguments.Checks.Internal.isNullOrEmpty;
import static tech.sirwellington.alchemy.arguments.ExceptionMapper.IDENTITY;
/**
*
* @author SirWellington
*/
@FluidAPIDesign
@StrategyPattern(role = CLIENT)
@Immutable
@Internal
final class AssertionBuilderImpl implements AssertionBuilder
{
private final static Logger LOG = LoggerFactory.getLogger(AssertionBuilderImpl.class);
private final AlchemyAssertion assertion;
private final ExceptionMapper exceptionMapper;
@Immutable
private final List arguments;
private final String overrideMessage;
private AssertionBuilderImpl(AlchemyAssertion assertion,
ExceptionMapper exceptionMapper,
String overrideMessage,
List arguments)
{
this.assertion = assertion;
this.exceptionMapper = exceptionMapper;
this.overrideMessage = overrideMessage;
this.arguments = arguments;
}
@Override
public AssertionBuilder usingMessage(String message)
{
Checks.Internal.checkThat(!isNullOrEmpty(message), "error message is empty");
ExceptionMapper newExceptionMapper;
if(exceptionMapper instanceof DynamicExceptionSupplier)
{
newExceptionMapper = createUpdatedDynamicExceptionMapperWithMessage(message);
}
else
{
newExceptionMapper = this.exceptionMapper;
}
return new AssertionBuilderImpl<>(assertion, newExceptionMapper, message, arguments);
}
static AssertionBuilderImpl checkThat(List arguments)
{
return new AssertionBuilderImpl<>(null, IDENTITY, "", arguments);
}
@Override
public AssertionBuilderImpl throwing(ExceptionMapper exceptionMapper)
{
Checks.Internal.checkNotNull(exceptionMapper, "exceptionMapper is null");
return new AssertionBuilderImpl<>(null, exceptionMapper, overrideMessage, arguments);
}
@Override
public AssertionBuilder throwing(Class exceptionClass)
{
Checks.Internal.checkNotNull(exceptionClass);
return this.throwing(new DynamicExceptionSupplier<>(exceptionClass, overrideMessage));
}
@Override
public AssertionBuilderImpl is(AlchemyAssertion assertion) throws Ex
{
Checks.Internal.checkNotNull(assertion, "assertion is null");
AssertionBuilderImpl newBuilder = new AssertionBuilderImpl<>(assertion, exceptionMapper, overrideMessage, arguments);
//Check this assertion
newBuilder.checkAssertion();
//Return the new one to allow further assertions on this argument
return newBuilder;
}
private void checkAssertion() throws Ex
{
Checks.Internal.checkState(assertion != null, "no assertion found");
Checks.Internal.checkState(exceptionMapper != null, "no exceptionMapper found");
FailedAssertionException caught = null;
try
{
arguments.forEach(assertion::check);
}
catch (FailedAssertionException ex)
{
caught = ex;
if (!Checks.Internal.isNullOrEmpty(overrideMessage))
{
caught.changeMessage(overrideMessage);
}
}
catch (RuntimeException ex)
{
handleUnexpectedException(ex);
}
if (exceptionOccured(caught))
{
handleFailedAssertion(caught);
}
}
private boolean exceptionOccured(FailedAssertionException caught)
{
return caught != null;
}
private void handleUnexpectedException(RuntimeException ex) throws Ex
{
LOG.warn("Assertion {} threw an unexpected exception. Only {} Exceptions are acceptable for Assertions.",
assertion,
FailedAssertionException.class.getSimpleName(),
ex);
FailedAssertionException wrappedException = new FailedAssertionException("wrapping unexpected exception", ex);
handleFailedAssertion(wrappedException);
}
private void handleFailedAssertion(FailedAssertionException caught) throws Ex
{
Ex mappedEx = exceptionMapper.apply(caught);
if (mappedEx != null)
{
throw mappedEx;
}
else
{
LOG.warn("Exception Mapper did not return a throwable. Swallowing exception", caught);
}
}
private ExceptionMapper createUpdatedDynamicExceptionMapperWithMessage(String message)
{
DynamicExceptionSupplier dynamicExceptionMapper = (DynamicExceptionSupplier) exceptionMapper;
Class exceptionClass = dynamicExceptionMapper.getExceptionClass();
return new DynamicExceptionSupplier<>(exceptionClass, message);
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy