Search in sources :

Example 1 with ValuePreparer

use of org.apache.sling.models.spi.ValuePreparer in project sling by apache.

the class ModelAdapterFactory method injectElement.

@CheckForNull
private RuntimeException injectElement(final InjectableElement element, final Object adaptable, @Nonnull final DisposalCallbackRegistry registry, final InjectCallback callback, @Nonnull final Map<ValuePreparer, Object> preparedValues) {
    InjectAnnotationProcessor annotationProcessor = null;
    String source = element.getSource();
    boolean wasInjectionSuccessful = false;
    // find an appropriate annotation processor
    for (InjectAnnotationProcessorFactory2 factory : injectAnnotationProcessorFactories2) {
        annotationProcessor = factory.createAnnotationProcessor(adaptable, element.getAnnotatedElement());
        if (annotationProcessor != null) {
            break;
        }
    }
    if (annotationProcessor == null) {
        for (InjectAnnotationProcessorFactory factory : injectAnnotationProcessorFactories) {
            annotationProcessor = factory.createAnnotationProcessor(adaptable, element.getAnnotatedElement());
            if (annotationProcessor != null) {
                break;
            }
        }
    }
    String name = getName(element, annotationProcessor);
    final Object injectionAdaptable = getAdaptable(adaptable, element, annotationProcessor);
    RuntimeException lastInjectionException = null;
    if (injectionAdaptable != null) {
        // prepare the set of injectors to process. if a source is given only use injectors with this name.
        final RankedServices<Injector> injectorsToProcess;
        if (StringUtils.isEmpty(source)) {
            injectorsToProcess = sortedInjectors;
        } else {
            injectorsToProcess = injectors.get(source);
            if (injectorsToProcess == null) {
                throw new IllegalArgumentException("No Sling Models Injector registered for source '" + source + "'.");
            }
        }
        // find the right injector
        for (Injector injector : injectorsToProcess) {
            if (name != null || injector instanceof AcceptsNullName) {
                Object preparedValue = injectionAdaptable;
                // only do the ValuePreparer optimization for the original adaptable
                if (injector instanceof ValuePreparer && adaptable == injectionAdaptable) {
                    final ValuePreparer preparer = (ValuePreparer) injector;
                    Object fromMap = preparedValues.get(preparer);
                    if (fromMap != null) {
                        preparedValue = fromMap;
                    } else {
                        preparedValue = preparer.prepareValue(injectionAdaptable);
                        preparedValues.put(preparer, preparedValue);
                    }
                }
                Object value = injector.getValue(preparedValue, name, element.getType(), element.getAnnotatedElement(), registry);
                if (value != null) {
                    lastInjectionException = callback.inject(element, value);
                    if (lastInjectionException == null) {
                        wasInjectionSuccessful = true;
                        break;
                    }
                }
            }
        }
    }
    // if injection failed, use default
    if (!wasInjectionSuccessful) {
        Result<Boolean> defaultInjectionResult = injectDefaultValue(element, annotationProcessor, callback);
        if (defaultInjectionResult.wasSuccessful()) {
            wasInjectionSuccessful = defaultInjectionResult.getValue();
            // log previous injection error, if there was any
            if (lastInjectionException != null && wasInjectionSuccessful) {
                log.debug("Although falling back to default value worked, injection into {} failed because of: " + lastInjectionException.getMessage(), element.getAnnotatedElement(), lastInjectionException);
            }
        } else {
            return defaultInjectionResult.getThrowable();
        }
    }
    // if default is not set, check if mandatory
    if (!wasInjectionSuccessful) {
        if (element.isOptional(annotationProcessor)) {
            // log previous injection error, if there was any
            if (lastInjectionException != null) {
                log.debug("Injection into optional element {} failed because of: " + lastInjectionException.getMessage(), element.getAnnotatedElement(), lastInjectionException);
            }
            if (element.isPrimitive()) {
                RuntimeException throwable = injectPrimitiveInitialValue(element, callback);
                if (throwable != null) {
                    return throwable;
                }
            }
        } else {
            if (lastInjectionException != null) {
                return lastInjectionException;
            } else {
                return new ModelClassException("No injector returned a non-null value!");
            }
        }
    }
    return null;
}
Also used : InjectAnnotationProcessorFactory2(org.apache.sling.models.spi.injectorspecific.InjectAnnotationProcessorFactory2) ValuePreparer(org.apache.sling.models.spi.ValuePreparer) InjectAnnotationProcessor(org.apache.sling.models.spi.injectorspecific.InjectAnnotationProcessor) Injector(org.apache.sling.models.spi.Injector) ModelClassException(org.apache.sling.models.factory.ModelClassException) AcceptsNullName(org.apache.sling.models.spi.AcceptsNullName) InjectAnnotationProcessorFactory(org.apache.sling.models.spi.injectorspecific.InjectAnnotationProcessorFactory) StaticInjectAnnotationProcessorFactory(org.apache.sling.models.spi.injectorspecific.StaticInjectAnnotationProcessorFactory) CheckForNull(javax.annotation.CheckForNull)

Example 2 with ValuePreparer

use of org.apache.sling.models.spi.ValuePreparer in project sling by apache.

the class ModelAdapterFactory method createObject.

private <ModelType> Result<ModelType> createObject(final Object adaptable, final ModelClass<ModelType> modelClass) throws InstantiationException, InvocationTargetException, IllegalAccessException {
    DisposalCallbackRegistryImpl registry = new DisposalCallbackRegistryImpl();
    ModelClassConstructor<ModelType> constructorToUse = getBestMatchingConstructor(adaptable, modelClass);
    if (constructorToUse == null) {
        return new Result<ModelType>(new ModelClassException("Unable to find a useable constructor for model " + modelClass.getType()));
    }
    final Map<ValuePreparer, Object> preparedValues = new HashMap<ValuePreparer, Object>(VALUE_PREPARERS_COUNT);
    final ModelType object;
    if (constructorToUse.getConstructor().getParameterTypes().length == 0) {
        // no parameters for constructor injection? instantiate it right away
        object = constructorToUse.getConstructor().newInstance();
    } else {
        // if this fails, make sure resources that may be claimed by injectors are cleared up again
        try {
            Result<ModelType> result = newInstanceWithConstructorInjection(constructorToUse, adaptable, modelClass, registry, preparedValues);
            if (!result.wasSuccessful()) {
                registry.onDisposed();
                return result;
            } else {
                object = result.getValue();
            }
        } catch (InstantiationException ex) {
            registry.onDisposed();
            throw ex;
        } catch (InvocationTargetException ex) {
            registry.onDisposed();
            throw ex;
        } catch (IllegalAccessException ex) {
            registry.onDisposed();
            throw ex;
        }
    }
    registerCallbackRegistry(object, registry);
    InjectCallback callback = new SetFieldCallback(object);
    InjectableField[] injectableFields = modelClass.getInjectableFields();
    MissingElementsException missingElements = new MissingElementsException("Could not inject all required fields into " + modelClass.getType());
    for (InjectableField field : injectableFields) {
        RuntimeException t = injectElement(field, adaptable, registry, callback, preparedValues);
        if (t != null) {
            missingElements.addMissingElementExceptions(new MissingElementException(field.getAnnotatedElement(), t));
        }
    }
    registry.seal();
    if (!missingElements.isEmpty()) {
        return new Result<ModelType>(missingElements);
    }
    try {
        invokePostConstruct(object);
    } catch (InvocationTargetException e) {
        return new Result<ModelType>(new PostConstructException("Post-construct method has thrown an exception for model " + modelClass.getType(), e.getCause()));
    } catch (IllegalAccessException e) {
        new Result<ModelType>(new ModelClassException("Could not call post-construct method for model " + modelClass.getType(), e));
    }
    return new Result<ModelType>(object);
}
Also used : PostConstructException(org.apache.sling.models.factory.PostConstructException) ConcurrentHashMap(java.util.concurrent.ConcurrentHashMap) HashMap(java.util.HashMap) WeakHashMap(java.util.WeakHashMap) ValuePreparer(org.apache.sling.models.spi.ValuePreparer) MissingElementsException(org.apache.sling.models.factory.MissingElementsException) InvocationTargetException(java.lang.reflect.InvocationTargetException) ModelClassException(org.apache.sling.models.factory.ModelClassException) InjectableField(org.apache.sling.models.impl.model.InjectableField) MissingElementException(org.apache.sling.models.factory.MissingElementException)

Example 3 with ValuePreparer

use of org.apache.sling.models.spi.ValuePreparer in project sling by apache.

the class ModelAdapterFactory method createInvocationHandler.

private <ModelType> Result<InvocationHandler> createInvocationHandler(final Object adaptable, final ModelClass<ModelType> modelClass) {
    InjectableMethod[] injectableMethods = modelClass.getInjectableMethods();
    final Map<Method, Object> methods = new HashMap<Method, Object>();
    SetMethodsCallback callback = new SetMethodsCallback(methods);
    MapBackedInvocationHandler handler = new MapBackedInvocationHandler(methods);
    DisposalCallbackRegistryImpl registry = new DisposalCallbackRegistryImpl();
    registerCallbackRegistry(handler, registry);
    final Map<ValuePreparer, Object> preparedValues = new HashMap<ValuePreparer, Object>(VALUE_PREPARERS_COUNT);
    MissingElementsException missingElements = new MissingElementsException("Could not create all mandatory methods for interface of model " + modelClass);
    for (InjectableMethod method : injectableMethods) {
        RuntimeException t = injectElement(method, adaptable, registry, callback, preparedValues);
        if (t != null) {
            missingElements.addMissingElementExceptions(new MissingElementException(method.getAnnotatedElement(), t));
        }
    }
    registry.seal();
    if (!missingElements.isEmpty()) {
        return new Result<InvocationHandler>(missingElements);
    }
    return new Result<InvocationHandler>(handler);
}
Also used : ConcurrentHashMap(java.util.concurrent.ConcurrentHashMap) HashMap(java.util.HashMap) WeakHashMap(java.util.WeakHashMap) ValuePreparer(org.apache.sling.models.spi.ValuePreparer) MissingElementsException(org.apache.sling.models.factory.MissingElementsException) InjectableMethod(org.apache.sling.models.impl.model.InjectableMethod) Method(java.lang.reflect.Method) InjectableMethod(org.apache.sling.models.impl.model.InjectableMethod) MissingElementException(org.apache.sling.models.factory.MissingElementException)

Aggregations

ValuePreparer (org.apache.sling.models.spi.ValuePreparer)3 HashMap (java.util.HashMap)2 WeakHashMap (java.util.WeakHashMap)2 ConcurrentHashMap (java.util.concurrent.ConcurrentHashMap)2 MissingElementException (org.apache.sling.models.factory.MissingElementException)2 MissingElementsException (org.apache.sling.models.factory.MissingElementsException)2 ModelClassException (org.apache.sling.models.factory.ModelClassException)2 InvocationTargetException (java.lang.reflect.InvocationTargetException)1 Method (java.lang.reflect.Method)1 CheckForNull (javax.annotation.CheckForNull)1 PostConstructException (org.apache.sling.models.factory.PostConstructException)1 InjectableField (org.apache.sling.models.impl.model.InjectableField)1 InjectableMethod (org.apache.sling.models.impl.model.InjectableMethod)1 AcceptsNullName (org.apache.sling.models.spi.AcceptsNullName)1 Injector (org.apache.sling.models.spi.Injector)1 InjectAnnotationProcessor (org.apache.sling.models.spi.injectorspecific.InjectAnnotationProcessor)1 InjectAnnotationProcessorFactory (org.apache.sling.models.spi.injectorspecific.InjectAnnotationProcessorFactory)1 InjectAnnotationProcessorFactory2 (org.apache.sling.models.spi.injectorspecific.InjectAnnotationProcessorFactory2)1 StaticInjectAnnotationProcessorFactory (org.apache.sling.models.spi.injectorspecific.StaticInjectAnnotationProcessorFactory)1