de.cosmocode.palava.core.aop.PalavaAspect.java Source code

Java tutorial

Introduction

Here is the source code for de.cosmocode.palava.core.aop.PalavaAspect.java

Source

/**
 * Copyright 2010 CosmoCode GmbH
 *
 * 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 de.cosmocode.palava.core.aop;

import com.google.common.base.Preconditions;
import com.google.common.collect.Iterables;
import com.google.inject.Binder;
import com.google.inject.Guice;
import com.google.inject.Inject;
import com.google.inject.Module;
import com.google.inject.Stage;
import com.google.inject.name.Named;
import de.cosmocode.commons.Throwables;
import de.cosmocode.palava.core.CoreConfig;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.Collections;

/**
 * Abstract palava {@link Aspect}.
 *
 * @author Willi Schoenborn
 * @since 2.9
 */
@Aspect("issingleton()")
public abstract class PalavaAspect {

    private static final Logger LOG = LoggerFactory.getLogger(PalavaAspect.class);

    private boolean injected;
    private boolean reinjectable;

    private final Module module = new Module() {

        @Override
        public void configure(Binder binder) {
            checkInjectable();
            final PalavaAspect self = PalavaAspect.this;

            if (injected) {
                LOG.trace("Re-injecting members on {}", self);
            } else {
                LOG.trace("Injecting members on {}", self);
            }

            binder.requestInjection(self);
        }

    };

    private boolean isNotInjected() {
        return !injected;
    }

    private void checkInjectable() {
        Preconditions.checkState(isNotInjected() || reinjectable, "Illegal attempt to reinject members on %s",
                this);
    }

    /**
     * Checks that this aspect has been injected.
     *
     * @deprecated use {@link #checkInjected()}
     * @throws IllegalStateException if members of this aspect have not yet been injected
     * @since 2.9
     */
    @Deprecated
    protected final void checkState() {
        Preconditions.checkState(injected, "Members have not been injected on %s", this);
    }

    /**
     * Checks that this aspect has not yet been injected.
     *
     * @throws IllegalStateException if members of this aspect have been injected already
     * @since 2.9
     */
    protected final void checkNotInjected() {
        Preconditions.checkState(!injected, "Members have been injected on %s already", this);
    }

    /**
     * Checks that this aspect has been injected.
     *
     * @throws IllegalStateException if members of this aspect have not yet been injected
     * @since 2.9
     */
    protected final void checkInjected() {
        Preconditions.checkState(injected, "Members have not been injected on %s", this);
    }

    /**
     * An injection point which marks this aspect as {@link #injected}.
     *
     * @throws IllegalStateException if this aspect is already injected and does not allow reinjection
     * @since 2.9
     */
    @Inject
    final void setInjected() {
        checkInjectable();
        this.injected = true;
    }

    /**
     * Optionally set {@link #reinjectable} of this aspect.
     *
     * @param reinjectable true if this aspect allows reinjection, false otherwise
     * @throws IllegalStateException if this aspect is already injected and does not allow reinjection
     * @since 2.9
     */
    @Inject(optional = true)
    final void setReinjectable(@Named(CoreConfig.REINJECTABLE_ASPECTS) boolean reinjectable) {
        this.reinjectable = reinjectable;
    }

    private Module[] append(Module[] modules) {
        final Module[] array = new Module[modules.length + 1];
        System.arraycopy(modules, 0, array, 0, modules.length);
        array[modules.length] = module;
        return array;
    }

    @Pointcut("!within(@de.cosmocode.palava.core.aop.SuppressInject *)")
    private void include() {

    }

    @Pointcut("call(com.google.inject.Injector com.google.inject.Guice.createInjector("
            + "com.google.inject.Module...)) && args(modules)")
    private void moduleArray(Module... modules) {

    }

    /**
     * An advice around {@link Guice#createInjector(Module...)} to inject members on this aspect.
     *
     * @param point   the proceeding joint point
     * @param modules the originally passed modules
     * @return the injector
     * @since 2.9
     */
    @Around("include() && moduleArray(modules)")
    public Object aroundModuleArray(ProceedingJoinPoint point, Module... modules) {
        try {
            return point.proceed(new Object[] { append(modules) });
            /* CHECKSTYLE:OFF */
        } catch (Throwable e) {
            /* CHECKSTYLE:ON */
            throw Throwables.sneakyThrow(e);
        }
    }

    @Pointcut("call(com.google.inject.Injector com.google.inject.Guice.createInjector("
            + "java.lang.Iterable)) && args(modules)")
    private void moduleIterable(Iterable modules) {

    }

    /**
     * An advice around {@link Guice#createInjector(Iterable)} to inject members on this aspect.
     *
     * @param point   the proceeding joint point
     * @param modules the originally passed modules
     * @return the injector
     * @since 2.9
     */
    @Around("include() && moduleIterable(modules)")
    public Object aroundModuleIterable(ProceedingJoinPoint point, Iterable modules) {
        try {
            return point.proceed(new Object[] { Iterables.concat(modules, Collections.singleton(module)) });
            /* CHECKSTYLE:OFF */
        } catch (Throwable e) {
            /* CHECKSTYLE:ON */
            throw Throwables.sneakyThrow(e);
        }
    }

    @Pointcut("call(com.google.inject.Injector com.google.inject.Guice.createInjector("
            + "com.google.inject.Stage, com.google.inject.Module...)) && args(stage, modules)")
    private void stageAndModuleArray(Stage stage, Module... modules) {

    }

    /**
     * An advice around {@link Guice#createInjector(Stage, Module...)} to inject members on this aspect.
     *
     * @param point   the proceeding joint point
     * @param stage   the originally passed stage
     * @param modules the originally passed modules
     * @return the injector
     * @since 2.9
     */
    @Around("include() && stageAndModuleArray(stage, modules)")
    public Object aroundStageAndModuleArray(ProceedingJoinPoint point, Stage stage, Module... modules) {
        try {
            return point.proceed(new Object[] { stage, append(modules) });
            /* CHECKSTYLE:OFF */
        } catch (Throwable e) {
            /* CHECKSTYLE:ON */
            throw Throwables.sneakyThrow(e);
        }
    }

    @Pointcut("call(com.google.inject.Injector com.google.inject.Guice.createInjector("
            + "com.google.inject.Stage, java.lang.Iterable)) && args(stage, modules)")
    private void stageAndModuleIterable(Stage stage, Iterable modules) {

    }

    /**
     * An advice around {@link Guice#createInjector(Stage, Iterable)} to inject members on this aspect.
     *
     * @param point   the proceeding joint point
     * @param stage   the originally passed stage
     * @param modules the originally passed stage
     * @return the injector
     * @since 2.9
     */
    @Around("include() && stageAndModuleIterable(stage, modules)")
    public Object aroundStageAndModuleIterable(ProceedingJoinPoint point, Stage stage, Iterable modules) {
        try {
            return point.proceed(new Object[] { stage, Iterables.concat(modules, Collections.singleton(module)) });
            /* CHECKSTYLE:OFF */
        } catch (Throwable e) {
            /* CHECKSTYLE:ON */
            throw Throwables.sneakyThrow(e);
        }
    }

}