add ChainTask for AsyncBackupAspect.aj

add ChainTask for AsyncBackupAspect.aj

package org.zstack.core.aspect;

import org.springframework.beans.factory.annotation.Autowired;
import org.zstack.core.cloudbus.CloudBus;
import org.zstack.core.errorcode.ErrorFacade;
import org.zstack.header.core.workflow.FlowRollback;
import org.zstack.header.errorcode.OperationFailureException;
import org.zstack.core.thread.ChainTask;
import org.zstack.core.thread.SyncTaskChain;
import org.zstack.header.core.workflow.FlowTrigger;
import org.zstack.header.core.*;
import org.zstack.header.errorcode.ErrorCode;
import org.zstack.header.exception.CloudRuntimeException;
import org.zstack.header.message.Message;
import org.zstack.utils.DebugUtils;
import org.zstack.utils.Utils;
import org.zstack.utils.logging.CLogger;

import java.util.List;

public aspect AsyncBackupAspect {
    private final CLogger logger = Utils.getLogger(AsyncBackupAspect.class);

    @Autowired
    private CloudBus bus;
    @Autowired
    private ErrorFacade errf;

    private boolean isAsyncBackup(Object backup) {
        return backup instanceof Message
                || backup instanceof Completion
                || backup instanceof ReturnValueCompletion
                || backup instanceof AsyncLatch
                || backup instanceof FlowTrigger
                || backup instanceof SyncTaskChain
                || backup instanceof NoErrorCompletion
                || backup instanceof FlowRollback
                || backup instanceof ChainTask;
    }

    private void backup(List<AsyncBackup> ancestors, Throwable t, boolean flipThrowable) {
        if (ancestors == null || ancestors.isEmpty()) {
            // throw original exception out if no backup specified
            if (t instanceof RuntimeException) {
                throw (RuntimeException)t;
            } else if (t instanceof Error) {
                throw (Error)t;
            } else {
                throw new CloudRuntimeException(t);
            }
        }

        for (AsyncBackup ancestor : ancestors) {
            if (!isAsyncBackup(ancestor)) {
                String info = String.format("%s is not a known AsyncBackup. Someone added this type but forgot changing AsyncBackupAspect, please file bug", ancestor.getClass().getName());
                DebugUtils.dumpStackTrace(info);
                return;
            }

            ErrorCode err = t instanceof OperationFailureException ? ((OperationFailureException) t).getErrorCode() : errf.throwableToInternalError(t);
            if (ancestor instanceof Completion) {
                ((Completion)ancestor).fail(err);
            } else if (ancestor instanceof ReturnValueCompletion) {
                ((ReturnValueCompletion)ancestor).fail(err);
            } else if (ancestor instanceof AsyncLatch) {
                ((AsyncLatch) ancestor).ack();
            } else if (ancestor instanceof FlowTrigger) {
                ((FlowTrigger) ancestor).fail(err);
            } else if (ancestor instanceof FlowRollback) {
                ((FlowRollback) ancestor).rollback();
            } else if (ancestor instanceof  SyncTaskChain) {
                ((SyncTaskChain) ancestor).next();
            } else if (ancestor instanceof NoErrorCompletion) {
                ((NoErrorCompletion) ancestor).done();
            } else if (ancestor instanceof Message) {
                bus.logExceptionWithMessageDump((Message) ancestor, t);
                bus.replyErrorByMessageType((Message) ancestor, err);
            } else {
                throw new CloudRuntimeException("should not be here");
            }
        }

        if (flipThrowable && t instanceof RuntimeException) {
            throw (RuntimeException)t;
        } else {
            logger.warn("unhandled exception happened", t);
        }
    }

    private void backup(List<AsyncBackup> ancestors, Throwable t) {
        backup(ancestors, t, false);
    }

    void around(org.zstack.header.core.AbstractCompletion completion) : this(completion) && execution(void org.zstack.header.core.Completion+.success()) {
        try {
            proceed(completion);
        } catch (Throwable  t) {
            backup(completion.getBackups(), t);
        }
    }

    void around(org.zstack.header.core.AbstractCompletion completion) : this(completion) && execution(void org.zstack.header.core.Completion+.fail(..)) {
        try {
            proceed(completion);
        } catch (Throwable  t) {
            backup(completion.getBackups(), t);
        }
    }

    void around(org.zstack.header.core.AbstractCompletion completion) : this(completion) && execution(void org.zstack.header.core.ReturnValueCompletion+.success(..)) {
        try {
            proceed(completion);
        } catch (Throwable  t) {
            backup(completion.getBackups(), t);
        }
    }

    void around(org.zstack.header.core.AbstractCompletion completion) : this(completion) && execution(void org.zstack.header.core.ReturnValueCompletion+.fail(..)) {
        try {
            proceed(completion);
        } catch (Throwable  t) {
            backup(completion.getBackups(), t);
        }
    }

    void around(org.zstack.header.core.AbstractCompletion completion) : this(completion) && execution(void org.zstack.header.core.NoErrorCompletion+.done()) {
        try {
            proceed(completion);
        } catch (Throwable  t) {
            backup(completion.getBackups(), t);
        }
    }

    void around(org.zstack.header.core.AbstractCompletion completion) : this(completion) && execution(void org.zstack.header.core.NopeCompletion+.success()) {
        try {
            proceed(completion);
        } catch (Throwable  t) {
            backup(completion.getBackups(), t);
        }
    }

    void around(org.zstack.header.core.AbstractCompletion completion) : this(completion) && execution(void org.zstack.header.core.NopeCompletion+.fail(..)) {
        try {
            proceed(completion);
        } catch (Throwable  t) {
            backup(completion.getBackups(), t);
        }
    }

    void around(org.zstack.header.core.AbstractCompletion completion) : this(completion) && execution(void org.zstack.core.cloudbus.CloudBusCallBack+.run(..)) {
        try {
            proceed(completion);
        } catch (Throwable  t) {
            backup(completion.getBackups(), t);
        }
    }

    void around(org.zstack.header.core.AbstractCompletion completion) : this(completion) && execution(void org.zstack.core.cloudbus.CloudBusListCallBack+.run(..)) {
        try {
            proceed(completion);
        } catch (Throwable  t) {
            backup(completion.getBackups(), t);
        }
    }

    void around(org.zstack.header.core.AbstractCompletion completion) : this(completion) && execution(void org.zstack.core.thread.ChainTask+.run(..)) {
        try {
            proceed(completion);
        } catch (Throwable  t) {
            backup(completion.getBackups(), t, true);
        }
    }

    void around(org.zstack.header.core.AbstractCompletion completion) : this(completion) && execution(void org.zstack.header.rest.AsyncRESTCallback+.timeout(..)) {
        try {
            proceed(completion);
        } catch (Throwable  t) {
            backup(completion.getBackups(), t);
        }
    }

    void around(org.zstack.header.core.AbstractCompletion completion) : this(completion) && execution(void org.zstack.header.rest.AsyncRESTCallback+.success(..)) {
        try {
            proceed(completion);
        } catch (Throwable  t) {
            backup(completion.getBackups(), t);
        }
    }

    void around(org.zstack.header.core.AbstractCompletion completion) : this(completion) && execution(void org.zstack.header.rest.AsyncRESTCallback+.fail(..)) {
        try {
            proceed(completion);
        } catch (Throwable  t) {
            backup(completion.getBackups(), t);
        }
    }

    void around(org.zstack.header.core.AbstractCompletion completion) : this(completion) && execution(void org.zstack.header.core.workflow.FlowDoneHandler+.handle(..)) {
        try {
            proceed(completion);
        } catch (Throwable  t) {
            backup(completion.getBackups(), t);
        }
    }

    void around(org.zstack.header.core.AbstractCompletion completion) : this(completion) && execution(void org.zstack.header.core.workflow.FlowErrorHandler+.handle(..)) {
        try {
            proceed(completion);
        } catch (Throwable  t) {
            backup(completion.getBackups(), t);
        }
    }

    void around(org.zstack.header.core.AbstractCompletion completion) : this(completion) && execution(void org.zstack.header.core.workflow.FlowFinallyHandler+.Finally(..)) {
        try {
            proceed(completion);
        } catch (Throwable  t) {
            backup(completion.getBackups(), t);
        }
    }
}

package org.zstack.core.aspect;

import org.springframework.beans.factory.annotation.Autowired;
import org.zstack.core.cloudbus.CloudBus;
import org.zstack.core.errorcode.ErrorFacade;
import org.zstack.header.core.workflow.FlowRollback;
import org.zstack.header.errorcode.OperationFailureException;
import org.zstack.core.thread.SyncTaskChain;
import org.zstack.header.core.workflow.FlowTrigger;
import org.zstack.header.core.*;
import org.zstack.header.errorcode.ErrorCode;
import org.zstack.header.exception.CloudRuntimeException;
import org.zstack.header.message.Message;
import org.zstack.utils.DebugUtils;
import org.zstack.utils.Utils;
import org.zstack.utils.logging.CLogger;

import java.util.List;

public aspect AsyncBackupAspect {
    private final CLogger logger = Utils.getLogger(AsyncBackupAspect.class);

    @Autowired
    private CloudBus bus;
    @Autowired
    private ErrorFacade errf;

    private boolean isAsyncBackup(Object backup) {
        return backup instanceof Message || backup instanceof Completion || backup instanceof ReturnValueCompletion
                || backup instanceof AsyncLatch
                || backup instanceof FlowTrigger || backup instanceof SyncTaskChain
                || backup instanceof NoErrorCompletion || backup instanceof FlowRollback;
    }

    private void backup(List<AsyncBackup> ancestors, Throwable t, boolean flipThrowable) {
        if (ancestors == null || ancestors.isEmpty()) {
            // throw original exception out if no backup specified
            if (t instanceof RuntimeException) {
                throw (RuntimeException)t;
            } else if (t instanceof Error) {
                throw (Error)t;
            } else {
                throw new CloudRuntimeException(t);
            }
        }

        for (AsyncBackup ancestor : ancestors) {
            if (!isAsyncBackup(ancestor)) {
                String info = String.format("%s is not a known AsyncBackup. Someone added this type but forgot changing AsyncBackupAspect, please file bug", ancestor.getClass().getName());
                DebugUtils.dumpStackTrace(info);
                return;
            }

            ErrorCode err = t instanceof OperationFailureException ? ((OperationFailureException) t).getErrorCode() : errf.throwableToInternalError(t);
            if (ancestor instanceof Completion) {
                ((Completion)ancestor).fail(err);
            } else if (ancestor instanceof ReturnValueCompletion) {
                ((ReturnValueCompletion)ancestor).fail(err);
            } else if (ancestor instanceof AsyncLatch) {
                ((AsyncLatch) ancestor).ack();
            } else if (ancestor instanceof FlowTrigger) {
                ((FlowTrigger) ancestor).fail(err);
            } else if (ancestor instanceof FlowRollback) {
                ((FlowRollback) ancestor).rollback();
            } else if (ancestor instanceof  SyncTaskChain) {
                ((SyncTaskChain) ancestor).next();
            } else if (ancestor instanceof NoErrorCompletion) {
                ((NoErrorCompletion) ancestor).done();
            } else if (ancestor instanceof Message) {
                bus.logExceptionWithMessageDump((Message) ancestor, t);
                bus.replyErrorByMessageType((Message) ancestor, err);
            } else {
                throw new CloudRuntimeException("should not be here");
            }
        }

        if (flipThrowable && t instanceof RuntimeException) {
            throw (RuntimeException)t;
        } else {
            logger.warn("unhandled exception happened", t);
        }
    }

    private void backup(List<AsyncBackup> ancestors, Throwable t) {
        backup(ancestors, t, false);
    }

    void around(org.zstack.header.core.AbstractCompletion completion) : this(completion) && execution(void org.zstack.header.core.Completion+.success()) {
        try {
            proceed(completion);
        } catch (Throwable  t) {
            backup(completion.getBackups(), t);
        }
    }

    void around(org.zstack.header.core.AbstractCompletion completion) : this(completion) && execution(void org.zstack.header.core.Completion+.fail(..)) {
        try {
            proceed(completion);
        } catch (Throwable  t) {
            backup(completion.getBackups(), t);
        }
    }

    void around(org.zstack.header.core.AbstractCompletion completion) : this(completion) && execution(void org.zstack.header.core.ReturnValueCompletion+.success(..)) {
        try {
            proceed(completion);
        } catch (Throwable  t) {
            backup(completion.getBackups(), t);
        }
    }

    void around(org.zstack.header.core.AbstractCompletion completion) : this(completion) && execution(void org.zstack.header.core.ReturnValueCompletion+.fail(..)) {
        try {
            proceed(completion);
        } catch (Throwable  t) {
            backup(completion.getBackups(), t);
        }
    }

    void around(org.zstack.header.core.AbstractCompletion completion) : this(completion) && execution(void org.zstack.header.core.NoErrorCompletion+.done()) {
        try {
            proceed(completion);
        } catch (Throwable  t) {
            backup(completion.getBackups(), t);
        }
    }

    void around(org.zstack.header.core.AbstractCompletion completion) : this(completion) && execution(void org.zstack.header.core.NopeCompletion+.success()) {
        try {
            proceed(completion);
        } catch (Throwable  t) {
            backup(completion.getBackups(), t);
        }
    }

    void around(org.zstack.header.core.AbstractCompletion completion) : this(completion) && execution(void org.zstack.header.core.NopeCompletion+.fail(..)) {
        try {
            proceed(completion);
        } catch (Throwable  t) {
            backup(completion.getBackups(), t);
        }
    }

    void around(org.zstack.header.core.AbstractCompletion completion) : this(completion) && execution(void org.zstack.core.cloudbus.CloudBusCallBack+.run(..)) {
        try {
            proceed(completion);
        } catch (Throwable  t) {
            backup(completion.getBackups(), t);
        }
    }

    void around(org.zstack.header.core.AbstractCompletion completion) : this(completion) && execution(void org.zstack.core.cloudbus.CloudBusListCallBack+.run(..)) {
        try {
            proceed(completion);
        } catch (Throwable  t) {
            backup(completion.getBackups(), t);
        }
    }

    void around(org.zstack.header.core.AbstractCompletion completion) : this(completion) && execution(void org.zstack.core.thread.ChainTask+.run(..)) {
        try {
            proceed(completion);
        } catch (Throwable  t) {
            backup(completion.getBackups(), t, true);
        }
    }

    void around(org.zstack.header.core.AbstractCompletion completion) : this(completion) && execution(void org.zstack.header.rest.AsyncRESTCallback+.timeout(..)) {
        try {
            proceed(completion);
        } catch (Throwable  t) {
            backup(completion.getBackups(), t);
        }
    }

    void around(org.zstack.header.core.AbstractCompletion completion) : this(completion) && execution(void org.zstack.header.rest.AsyncRESTCallback+.success(..)) {
        try {
            proceed(completion);
        } catch (Throwable  t) {
            backup(completion.getBackups(), t);
        }
    }

    void around(org.zstack.header.core.AbstractCompletion completion) : this(completion) && execution(void org.zstack.header.rest.AsyncRESTCallback+.fail(..)) {
        try {
            proceed(completion);
        } catch (Throwable  t) {
            backup(completion.getBackups(), t);
        }
    }

    void around(org.zstack.header.core.AbstractCompletion completion) : this(completion) && execution(void org.zstack.header.core.workflow.FlowDoneHandler+.handle(..)) {
        try {
            proceed(completion);
        } catch (Throwable  t) {
            backup(completion.getBackups(), t);
        }
    }

    void around(org.zstack.header.core.AbstractCompletion completion) : this(completion) && execution(void org.zstack.header.core.workflow.FlowErrorHandler+.handle(..)) {
        try {
            proceed(completion);
        } catch (Throwable  t) {
            backup(completion.getBackups(), t);
        }
    }

    void around(org.zstack.header.core.AbstractCompletion completion) : this(completion) && execution(void org.zstack.header.core.workflow.FlowFinallyHandler+.Finally(..)) {
        try {
            proceed(completion);
        } catch (Throwable  t) {
            backup(completion.getBackups(), t);
        }
    }
}


- Remove pointcut to deleted interface - Reflect new .fp package in pointcut

package tlc2.tool.distributed;

public aspect RMIMethodMonitorAspect {

	// catch all method calls to RMI methods
	pointcut callToRemoteMethod() :
		   execution(* tlc2.tool.distributed.InternRMI.*(..))
		|| execution(* tlc2.tool.distributed.TLCServerRMI.*(..))
		|| execution(* tlc2.tool.distributed.TLCWorkerRMI.*(..))
		|| execution(* tlc2.tool.distributed.fp.FPSetRMI.*(..))

	before(): (callToRemoteMethod()) {
		RMIMethodMonitor.entering(thisJoinPoint);
	}
}

package tlc2.tool.distributed;

public aspect RMIMethodMonitorAspect {

	// catch all method calls to RMI methods
	pointcut callToRemoteMethod() :
		   execution(* tlc2.tool.distributed.InternRMI.*(..))
		|| execution(* tlc2.tool.distributed.TLCServerRMI.*(..))
		|| execution(* tlc2.tool.distributed.TLCWorkerRMI.*(..))
		|| execution(* tlc2.tool.distributed.FPSetRMI.*(..))
		|| execution(* tlc2.tool.distributed.FPIntSetRMI.*(..));

	before(): (callToRemoteMethod()) {
		RMIMethodMonitor.entering(thisJoinPoint);
	}
}


warning fixes

warning fixes

Signed-off-by: Ketoth Xupack <2ff7bd69a79a23dbf64ebd5846a612566f93fbf7@gmail.com>

package org.nohope.validation;

import org.aspectj.lang.annotation.SuppressAjWarnings;
import org.aspectj.lang.reflect.MethodSignature;

import javax.annotation.Nonnull;
import javax.annotation.meta.When;
import java.lang.annotation.Annotation;
import java.lang.reflect.Method;

@SuppressWarnings({
        "StringBufferReplaceableByString",
        "UtilityClassWithoutPrivateConstructor"
})
public final aspect NotNullAspect {

    // searches for all methods have at last one parameter annotated with @Nonnull
    pointcut nonNullParameter():
            execution(* *.*(.., @javax.annotation.Nonnull (*), ..));

    // searches for all methods which returns any reference type and annotated with @Nonnull
    pointcut validatedReturnValue():
            execution(@javax.annotation.Nonnull Object+ *.*(..));

    @SuppressAjWarnings
    after() returning(final Object ret): validatedReturnValue() {
        final MethodSignature sig = (MethodSignature) thisJoinPoint.getSignature();
        if (ret == null) {
            throw new IllegalStateException(new StringBuilder("@Nonnull method ")
                    .append(toString(sig))
                    .append(" must not return null")
                    .toString()
            );
        }
    }

    @SuppressAjWarnings
    before(): nonNullParameter() {
        final MethodSignature sig = (MethodSignature) thisJoinPoint.getSignature();
        final Method method = sig.getMethod();
        final Annotation[][] annotations = method.getParameterAnnotations();

        int i = 1;
        for (final Object obj : thisJoinPoint.getArgs()) {
            Nonnull a = null;
            for (Annotation annotation : annotations[i - 1]) {
                if (annotation instanceof Nonnull) {
                    a = (Nonnull) annotation;
                    break;
                }
            }

            if (obj == null && a != null && a.when() == When.ALWAYS) {
                throw new IllegalArgumentException(new StringBuilder("Argument ")
                        .append(i)
                        .append(" for @Nonnull parameter of ")
                        .append(toString(sig))
                        .append(" must not be null")
                        .toString()
                );
            }
            i++;
        }
    }

    private static StringBuilder toString(final MethodSignature sig) {
        final Method method = sig.getMethod();
        final Class[] args = method.getParameterTypes();
        final StringBuilder builder = new StringBuilder();
        builder.append('\'')
               .append(method.getReturnType().getSimpleName())
               .append(" ")
               .append(sig.getDeclaringType().getCanonicalName())
               .append('.')
               .append(method.getName())
               .append('(');
        boolean started = true;
        for (final Class arg : args) {
            if (!started) {
                builder.append(", ");
            } else {
                started = false;
            }
            builder.append(arg.getCanonicalName());
        }
        builder.append(")'");
        return builder;
    }
}

package org.nohope.validation;

import org.aspectj.lang.reflect.MethodSignature;

import javax.annotation.Nonnull;
import javax.annotation.meta.When;
import java.lang.annotation.Annotation;
import java.lang.reflect.Method;

@SuppressWarnings({
        "StringBufferReplaceableByString",
        "UtilityClassWithoutPrivateConstructor"
})
public final aspect NotNullAspect {

    // searches for all methods have at last one parameter annotated with @Nonnull
    pointcut nonNullParameter():
            execution(* *.*(.., @javax.annotation.Nonnull (*), ..));

    // searches for all methods which returns any reference type and annotated with @Nonnull
    pointcut validatedReturnValue():
            execution(@javax.annotation.Nonnull Object+ *.*(..));

    after() returning(final Object ret): validatedReturnValue() {
        final MethodSignature sig = (MethodSignature) thisJoinPoint.getSignature();
        if (ret == null) {
            throw new IllegalStateException(new StringBuilder("@Nonnull method ")
                    .append(toString(sig))
                    .append(" must not return null")
                    .toString()
            );
        }
    }

    before(): nonNullParameter() {
        final MethodSignature sig = (MethodSignature) thisJoinPoint.getSignature();
        final Method method = sig.getMethod();
        final Annotation[][] annotations = method.getParameterAnnotations();

        int i = 1;
        for (final Object obj : thisJoinPoint.getArgs()) {
            Nonnull a = null;
            for (Annotation annotation : annotations[i - 1]) {
                if (annotation instanceof Nonnull) {
                    a = (Nonnull) annotation;
                    break;
                }
            }

            if (obj == null && a != null && a.when() == When.ALWAYS) {
                throw new IllegalArgumentException(new StringBuilder("Argument ")
                        .append(i)
                        .append(" for @Nonnull parameter of ")
                        .append(toString(sig))
                        .append(" must not be null")
                        .toString()
                );
            }
            i++;
        }
    }

    private static StringBuilder toString(final MethodSignature sig) {
        final Method method = sig.getMethod();
        final Class[] args = method.getParameterTypes();
        final StringBuilder builder = new StringBuilder();
        builder.append('\'')
               .append(method.getReturnType().getSimpleName())
               .append(" ")
               .append(sig.getDeclaringType().getCanonicalName())
               .append('.')
               .append(method.getName())
               .append('(');
        boolean started = true;
        for (final Class arg : args) {
            if (!started) {
                builder.append(", ");
            } else {
                started = false;
            }
            builder.append(arg.getCanonicalName());
        }
        builder.append(")'");
        return builder;
    }
}


added more meaningful log messages

added more meaningful log messages

/**
 * palava - a java-php-bridge
 * Copyright (C) 2007-2010  CosmoCode GmbH
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2
 * of the License, or (at your option) any later version.
 *
 * This program 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.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
 * MA  02110-1301, USA.
 */

package de.cosmocode.palava.jta;

import javax.transaction.NotSupportedException;
import javax.transaction.Status;
import javax.transaction.SystemException;
import javax.transaction.UserTransaction;

import org.aspectj.lang.annotation.SuppressAjWarnings;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.google.common.base.Preconditions;
import com.google.inject.Inject;
import com.google.inject.Provider;

import de.cosmocode.palava.core.aop.AbstractPalavaAspect;

public abstract aspect AbstractUserTransactionAspect extends AbstractPalavaAspect issingleton() {

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

    private Provider<UserTransaction> provider;

    @Inject
    void setProvider(Provider<UserTransaction> provider) {
        this.provider = Preconditions.checkNotNull(provider, "Provider");
    }

    protected abstract pointcut transactional();

    @SuppressAjWarnings("adviceDidNotMatch")
    Object around(): transactional() {
        final UserTransaction tx = provider.get();
        LOG.trace("Using transaction {}", tx);

        final boolean local;

        try {
            local = tx.getStatus() == Status.STATUS_NO_TRANSACTION;
        } catch (SystemException e) {
            throw new IllegalStateException(e);
        }

        if (local) {
            LOG.trace("Beginning automatic transaction {}", tx);
            try {
                tx.begin();
            } catch (NotSupportedException e) {
                throw new IllegalStateException(e);
            } catch (SystemException e) {
                throw new IllegalStateException(e);
            }
        } else {
            LOG.trace("Transaction {} already active", tx);
        }

        final Object returnValue;

        try {
            returnValue = proceed();
        } catch (Exception e) {
            LOG.error("Exception inside automatic transaction context", e);
            try {
                if (local && tx.getStatus() == Status.STATUS_ACTIVE) {
                    LOG.info("Rolling back local/active transaction {}", tx);
                    tx.rollback();
                } else {
                    LOG.debug("Setting transaction {} as rollback only", tx);
                    tx.setRollbackOnly();
                }
            } catch (SystemException inner) {
                throw new IllegalStateException(inner);
            }
            throw new IllegalStateException(e);
        }

        final int status;

        try {
            status = tx.getStatus();
        } catch (SystemException e) {
            throw new IllegalStateException(e);
        }

        if (local) {
            if (status == Status.STATUS_MARKED_ROLLBACK) {
                try {
                    LOG.trace("Rolling back marked transaction {}", tx);
                    tx.rollback();
                } catch (SystemException e) {
                    throw new IllegalStateException(e);
                }
            } else {
                try {
                    tx.commit();
                    LOG.trace("Committed automatic transaction {}", tx);
                } catch (Exception e) {
                    LOG.error("Commit in automatic transaction context failed", e);
                    try {
                        LOG.info("Rolling back transaction {}", tx);
                        tx.rollback();
                    } catch (SystemException inner) {
                        throw new IllegalStateException(inner);
                    }
                    throw new IllegalStateException(e);
                }
            }
        }

        return returnValue;
    }

}

/**
 * palava - a java-php-bridge
 * Copyright (C) 2007-2010  CosmoCode GmbH
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2
 * of the License, or (at your option) any later version.
 *
 * This program 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.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
 * MA  02110-1301, USA.
 */

package de.cosmocode.palava.jta;

import javax.transaction.NotSupportedException;
import javax.transaction.Status;
import javax.transaction.SystemException;
import javax.transaction.UserTransaction;

import org.aspectj.lang.annotation.SuppressAjWarnings;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.google.common.base.Preconditions;
import com.google.inject.Inject;
import com.google.inject.Provider;

import de.cosmocode.palava.core.aop.AbstractPalavaAspect;

public abstract aspect AbstractUserTransactionAspect extends AbstractPalavaAspect issingleton() {

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

    private Provider<UserTransaction> provider;

    @Inject
    void setProvider(Provider<UserTransaction> provider) {
        this.provider = Preconditions.checkNotNull(provider, "Provider");
    }

    protected abstract pointcut transactional();

    @SuppressAjWarnings("adviceDidNotMatch")
    Object around(): transactional() {
        final UserTransaction tx = provider.get();
        LOG.trace("Using transaction {}", tx);

        final boolean local;

        try {
            local = tx.getStatus() == Status.STATUS_NO_TRANSACTION;
        } catch (SystemException e) {
            throw new IllegalStateException(e);
        }

        if (local) {
            LOG.trace("Beginning automatic transaction");
            try {
                tx.begin();
            } catch (NotSupportedException e) {
                throw new IllegalStateException(e);
            } catch (SystemException e) {
                throw new IllegalStateException(e);
            }
        } else {
            LOG.trace("Transaction already active");
        }

        final Object returnValue;

        try {
            returnValue = proceed();
        } catch (Exception e) {
            LOG.error("Exception inside automatic transaction context", e);
            try {
                if (local && tx.getStatus() == Status.STATUS_ACTIVE) {
                    tx.rollback();
                } else {
                    tx.setRollbackOnly();
                }
            } catch (SystemException inner) {
                throw new IllegalStateException(inner);
            }
            throw new IllegalStateException(e);
        }

        final int status;

        try {
            status = tx.getStatus();
        } catch (SystemException e) {
            throw new IllegalStateException(e);
        }

        if (local) {
            if (status == Status.STATUS_MARKED_ROLLBACK) {
                try {
                    tx.rollback();
                } catch (SystemException e) {
                    throw new IllegalStateException(e);
                }
            } else {
                try {
                    tx.commit();
                    LOG.trace("Committed automatic transaction");
                } catch (Exception e) {
                    LOG.error("Commit in automatic transaction context failed", e);
                    try {
                        tx.rollback();
                    } catch (SystemException inner) {
                        throw new IllegalStateException(inner);
                    }
                    throw new IllegalStateException(e);
                }
            }
        }

        return returnValue;
    }

}


static

static

/*
 * Copyright (c) 2013 original authors
 *
 * 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.eigengo.monitor.agent.akka;

import akka.actor.ActorCell;
import akka.actor.ActorRef;
import akka.actor.Props;

/**
 * Centralises the pointcuts
 */
abstract aspect Pointcuts {

    /**
     * Pointcut for {@code ActorCell.receiveMessage(msg)}, extracting the {@code ActorCell} and the message being received
     */
    static pointcut actorCellReceiveMessage(ActorCell actorCell, Object msg) : target(actorCell) &&
            call(* akka.actor.ActorCell.receiveMessage(..)) && args(msg);

    /**
     * Pointcut for {@code ActorCell.handleInvokeFailure(_, failure)}, extracting the {@code ActorCell} and the
     * cause of the failure
     */
    static pointcut actorCellHandleInvokeFailure(ActorCell actorCell, Throwable failure) : target(actorCell) &&
            execution(* akka.actor.ActorCell.handleInvokeFailure(..)) && args(*, failure);

    /**
     * Pointcut for the {@code EventStream.publish(event)} method, extracting just the event
     */
    static pointcut eventStreamPublish(Object event) :
            execution(* akka.event.EventStream.publish(..)) && args(event);

    /**
     * Pointcut for the {@code actorOf} method in {@code ActorRefFactory} implementations. You would typically use
     * it in the {@code after returning()} advices.
     */
    private static pointcut unnamedActorOf(Props props) : execution(* akka.actor.ActorRefFactory+.actorOf(*)) && args(props);
    /**
     * Pointcut for the {@code actorOf} method in {@code ActorRefFactory} implementations where actor is named on creation
     */
    private static pointcut namedActorOf(Props props) : execution(* akka.actor.ActorRefFactory+.actorOf(*,*)) && args(props, *);
    /**
     * Public pointcut for retrieving Props instance used by {@code actorOf} method in {@code ActorRefFactory}
     */
    static pointcut anyActorOf(Props props) : namedActorOf(props) || unnamedActorOf(props);

    /**
     * Pointcut for {@code ActorCell.stop(actor)} method, extracting the {@code ActorRef}
     */
    static pointcut actorCellStop(ActorRef actor) : execution(* akka.actor.ActorCell.stop(..)) && args(actor);

    /**
     * Pointcut for {@code ActorCell.stop()} method, extracting the targeted {@code ActorCell}
     */
    static pointcut actorCellInternalStop(ActorCell actorCell) : target(actorCell) && execution(* akka.actor.ActorCell.stop());
}

/*
 * Copyright (c) 2013 original authors
 *
 * 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.eigengo.monitor.agent.akka;

import akka.actor.ActorCell;
import akka.actor.ActorRef;
import akka.actor.Props;

/**
 * Centralises the pointcuts
 */
abstract aspect Pointcuts {

    /**
     * Pointcut for {@code ActorCell.receiveMessage(msg)}, extracting the {@code ActorCell} and the message being received
     */
    static pointcut actorCellReceiveMessage(ActorCell actorCell, Object msg) : target(actorCell) &&
            call(* akka.actor.ActorCell.receiveMessage(..)) && args(msg);

    /**
     * Pointcut for {@code ActorCell.handleInvokeFailure(_, failure)}, extracting the {@code ActorCell} and the
     * cause of the failure
     */
    static pointcut actorCellHandleInvokeFailure(ActorCell actorCell, Throwable failure) : target(actorCell) &&
            execution(* akka.actor.ActorCell.handleInvokeFailure(..)) && args(*, failure);

    /**
     * Pointcut for the {@code EventStream.publish(event)} method, extracting just the event
     */
    static pointcut eventStreamPublish(Object event) :
            execution(* akka.event.EventStream.publish(..)) && args(event);

    /**
     * Pointcut for the {@code actorOf} method in {@code ActorRefFactory} implementations. You would typically use
     * it in the {@code after returning()} advices.
     */
    private pointcut unnamedActorOf(Props props) : execution(* akka.actor.ActorRefFactory+.actorOf(*)) && args(props);
    /**
     * Pointcut for the {@code actorOf} method in {@code ActorRefFactory} implementations where actor is named on creation
     */
    private pointcut namedActorOf(Props props) : execution(* akka.actor.ActorRefFactory+.actorOf(*,*)) && args(props, *);
    /**
     * Public pointcut for retrieving Props instance used by {@code actorOf} method in {@code ActorRefFactory}
     */
    pointcut anyActorOf(Props props) : namedActorOf(props) || unnamedActorOf(props);

    /**
     * Pointcut for {@code ActorCell.stop(actor)} method, extracting the {@code ActorRef}
     */
    static pointcut actorCellStop(ActorRef actor) : execution(* akka.actor.ActorCell.stop(..)) && args(actor);

    /**
     * Pointcut for {@code ActorCell.stop()} method, extracting the targeted {@code ActorCell}
     */
    static pointcut actorCellInternalStop(ActorCell actorCell) : target(actorCell) && execution(* akka.actor.ActorCell.stop());
}


Fix job submission when running against an insecure cluster.

// Licensed to Cloudera, Inc. under one
// or more contributor license agreements.  See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership.  Cloudera, Inc. licenses this file
// to you 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.apache.hadoop.security;

import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.mapred.*;
import org.apache.hadoop.security.Credentials;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

public aspect JobClientTrace {
  private static final Log LOG = LogFactory.getLog(JobClientTracer.class);

  JobClientTrace() {
    LOG.info("Hue job submission aspect loaded.");
  }

  RunningJob around(JobConf conf):
    call(RunningJob JobClient.submitJobInternal(JobConf)) && args(conf) {
    RunningJob ret = proceed(conf);
    JobClientTracer.getInstance().submittedJob(ret);
    return ret;
  }

  /**
   * The JobClient assumes that the user is authenticated via kerberos for the
   * purpose of job submission, and thus that delegation tokens for the NN(s)
   * can be retrieved. This doesn't work, however, in the case that the job is
   * actually being submitted to the JT via an MR delegation token, because new
   * delegation tokens can't be retrieved if one is only authenticated via
   * delegation tokens. The work-around here is to pre-fetch NN delegation
   * tokens from jobsubd, and pass them in. We set the
   * mapreduce.job.credentials.binary here because this happens
   * immediately before we try to fill the token cache with delegation tokens
   * from the NN(s).
   */
  void around(Configuration conf, Credentials credentials):
    call(void JobClient.readTokensFromFiles(Configuration, Credentials)) && args(conf, credentials) {

    String hadoopTokenFileLocation = System.getenv("HADOOP_TOKEN_FILE_LOCATION");
    if (hadoopTokenFileLocation != null) {
      conf.set("mapreduce.job.credentials.binary", System.getenv("HADOOP_TOKEN_FILE_LOCATION"));
      conf.setBoolean("mapreduce.job.complete.cancel.delegation.tokens", false);
    }
    proceed(conf, credentials);
  }
}

// Licensed to Cloudera, Inc. under one
// or more contributor license agreements.  See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership.  Cloudera, Inc. licenses this file
// to you 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.apache.hadoop.security;

import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.mapred.*;
import org.apache.hadoop.security.Credentials;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

public aspect JobClientTrace {
  private static final Log LOG = LogFactory.getLog(JobClientTracer.class);

  JobClientTrace() {
    LOG.info("Hue job submission aspect loaded.");
  }

  RunningJob around(JobConf conf):
    call(RunningJob JobClient.submitJobInternal(JobConf)) && args(conf) {
    RunningJob ret = proceed(conf);
    JobClientTracer.getInstance().submittedJob(ret);
    return ret;
  }

  /**
   * The JobClient assumes that the user is authenticated via kerberos for the
   * purpose of job submission, and thus that delegation tokens for the NN(s)
   * can be retrieved. This doesn't work, however, in the case that the job is
   * actually being submitted to the JT via an MR delegation token, because new
   * delegation tokens can't be retrieved if one is only authenticated via
   * delegation tokens. The work-around here is to pre-fetch NN delegation
   * tokens from jobsubd, and pass them in. We set the
   * mapreduce.job.credentials.binary here because this happens
   * immediately before we try to fill the token cache with delegation tokens
   * from the NN(s).
   */
  void around(Configuration conf, Credentials credentials):
    call(void JobClient.readTokensFromFiles(Configuration, Credentials)) && args(conf, credentials) {
    conf.set("mapreduce.job.credentials.binary", System.getenv("HADOOP_TOKEN_FILE_LOCATION"));
    conf.setBoolean("mapreduce.job.complete.cancel.delegation.tokens", false);
    proceed(conf, credentials);
  }
}


Remove stale HierarchyResolver.remember around advice.

The around code currently breaks running JUnit tests in Java projects that use
lambdas. This is because the cast to SourceTypeBinding fails on lambda bindings.
Eclipse suppresses the ClassCastException and tests just do not run.

As far as I can tell, there is actually no Scala IDE-specific code in this
"remember" advice anyway. It was added in 2009 by Miles, and looks exactly like
the code it's replacing in older releases of Eclipse:

https://github.com/eclipse/eclipse.jdt.core/blob/R3_2_maintenance/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/hierarchy/HierarchyResolver.java#L347

(E.g. unlike most advice, it was not calling proceed/etc., but instead was just
a raw copy/paste of the original code. Probably well intentioned while trying
to get things to work.)

However, newer versions of Eclipse have added an instanceof check to handle lambads:

https://github.com/eclipse/eclipse.jdt.core/blob/master/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/hierarchy/HierarchyResolver.java#L413

Which means this copy/paste of the code is now stale.

Instead of updating this code to match newer version of Eclipse, given
it looks unneeded, I've just removed it.

/*
 * Copyright 2005-2010 LAMP/EPFL
 */
// $Id$

package scala.tools.eclipse.contribution.weaving.jdt.cfprovider;

import java.util.HashSet;

import org.eclipse.core.filebuffers.FileBuffers;
import org.eclipse.core.filebuffers.ITextFileBuffer;
import org.eclipse.core.filebuffers.ITextFileBufferManager;
import org.eclipse.core.filebuffers.LocationKind;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.jdt.core.IBuffer;
import org.eclipse.jdt.core.IClassFile;
import org.eclipse.jdt.core.IImportDeclaration;
import org.eclipse.jdt.core.IJavaElement;
import org.eclipse.jdt.core.IOpenable;
import org.eclipse.jdt.core.IType;
import org.eclipse.jdt.core.ITypeRoot;
import org.eclipse.jdt.core.JavaModelException;
import org.eclipse.jdt.core.dom.CompilationUnit;
import org.eclipse.jdt.core.search.TypeNameMatch;
import org.eclipse.jdt.internal.compiler.CompilationResult;
import org.eclipse.jdt.internal.compiler.ast.ASTNode;
import org.eclipse.jdt.internal.compiler.ast.CompilationUnitDeclaration;
import org.eclipse.jdt.internal.compiler.ast.ImportReference;
import org.eclipse.jdt.internal.compiler.ast.TypeDeclaration;
import org.eclipse.jdt.internal.compiler.ast.TypeReference;
import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants;
import org.eclipse.jdt.internal.compiler.env.IBinaryType;
import org.eclipse.jdt.internal.compiler.env.ICompilationUnit;
import org.eclipse.jdt.internal.compiler.env.IGenericType;
import org.eclipse.jdt.internal.compiler.env.ISourceImport;
import org.eclipse.jdt.internal.compiler.env.ISourceType;
import org.eclipse.jdt.internal.compiler.env.NameEnvironmentAnswer;
import org.eclipse.jdt.internal.compiler.lookup.ReferenceBinding;
import org.eclipse.jdt.internal.compiler.lookup.SourceTypeBinding;
import org.eclipse.jdt.internal.compiler.parser.Parser;
import org.eclipse.jdt.internal.compiler.parser.SourceTypeConverter;
import org.eclipse.jdt.internal.core.BinaryType;
import org.eclipse.jdt.internal.core.ClassFile;
import org.eclipse.jdt.internal.core.CompilationUnitElementInfo;
import org.eclipse.jdt.internal.core.ImportDeclaration;
import org.eclipse.jdt.internal.core.JavaElement;
import org.eclipse.jdt.internal.core.BufferManager;
import org.eclipse.jdt.internal.core.NameLookup;
import org.eclipse.jdt.internal.core.Openable;
import org.eclipse.jdt.internal.core.PackageFragment;
import org.eclipse.jdt.internal.core.SearchableEnvironment;
import org.eclipse.jdt.internal.core.SourceMapper;
import org.eclipse.jdt.internal.core.SourceType;
import org.eclipse.jdt.internal.core.SourceTypeElementInfo;
import org.eclipse.jdt.internal.core.hierarchy.HierarchyResolver;
import org.eclipse.jdt.internal.core.hierarchy.HierarchyType;
import org.eclipse.jdt.internal.core.util.Util;
import org.eclipse.jdt.internal.corext.util.OpenTypeHistory;
import org.eclipse.jdt.internal.ui.filters.InnerClassFilesFilter;
import org.eclipse.jdt.ui.SharedASTProvider;
import org.eclipse.jface.viewers.Viewer;

import scala.tools.eclipse.contribution.weaving.jdt.IScalaClassFile;
import scala.tools.eclipse.contribution.weaving.jdt.IScalaElement;

@SuppressWarnings("restriction")
public privileged aspect ClassFileProviderAspect {

  pointcut classFileCreations(PackageFragment parent, String name) :
    call(protected ClassFile.new(PackageFragment, String)) &&
    within(org.eclipse.jdt..*) &&
    args(parent, name);

  pointcut getTypeName(ClassFile cf) :
    execution(public String ClassFile.getTypeName()) &&
    target(cf);

  // For 3.6
  pointcut mapSource(ClassFile cf, SourceMapper mapper, IBinaryType info, IClassFile owner) :
    execution(IBuffer ClassFile.mapSource(SourceMapper, IBinaryType, IClassFile)) &&
    target(cf) &&
    target(IScalaClassFile) &&
    args(mapper, info, owner);

  // For 3.5
  pointcut mapSource2(ClassFile cf, SourceMapper mapper, IBinaryType info) :
    execution(IBuffer ClassFile.mapSource(SourceMapper, IBinaryType)) &&
    target(cf) &&
    target(IScalaClassFile) &&
    args(mapper, info);

  pointcut getSourceFileName(BinaryType bt) :
    execution(String BinaryType.getSourceFileName(IBinaryType)) &&
    target(bt);

  pointcut select(Viewer viewer, Object parentElement, Object element) :
    execution(boolean InnerClassFilesFilter.select(Viewer, Object, Object)) &&
    args(viewer, parentElement, element);

  pointcut getChildren(BinaryType bt) :
    execution(IJavaElement[] BinaryType.getChildren()) &&
    target(bt);

  pointcut getAST(ITypeRoot element, SharedASTProvider.WAIT_FLAG waitFlag, IProgressMonitor progressMonitor) :
    execution(CompilationUnit SharedASTProvider.getAST(ITypeRoot, SharedASTProvider.WAIT_FLAG, IProgressMonitor)) &&
    args(element, waitFlag, progressMonitor);

  pointcut resolve(HierarchyResolver hr, IGenericType suppliedType) :
    execution(void HierarchyResolver.resolve(IGenericType)) &&
    target(hr) &&
    args(suppliedType);

  pointcut acceptType(IType type, int acceptFlags, boolean isSourceType) :
    execution(boolean NameLookup.acceptType(IType, int, boolean)) &&
    args(type, acceptFlags, isSourceType);

  pointcut find(SearchableEnvironment se, String typeName, String packageName) :
    execution(NameEnvironmentAnswer find(String, String)) &&
    target(se) &&
    args(typeName, packageName);

  pointcut convert(SourceTypeConverter stc, ISourceType[] sourceTypes, CompilationResult compilationResult) :
    execution(CompilationUnitDeclaration SourceTypeConverter.convert(ISourceType[], CompilationResult)) &&
    target(stc) &&
    args(sourceTypes, compilationResult);

  pointcut getAncestor(JavaElement je, int ancestorType) :
    execution(IJavaElement JavaElement.getAncestor(int)) &&
    target(je) &&
    args(ancestorType);

  pointcut isContainerDirty(TypeNameMatch match) :
    execution(boolean OpenTypeHistory.isContainerDirty(TypeNameMatch)) &&
    args(match);

  ClassFile around(PackageFragment parent, String name) :
    classFileCreations(parent, name) {

    ClassFile javaClassFile = proceed(parent, name);
    byte[] bytes;

    try {
        for (IClassFileProvider provider : ClassFileProviderRegistry.getInstance().getProviders()) {
          if (provider.isInteresting(javaClassFile)) {
            bytes = javaClassFile.getBytes();
            ClassFile cf = provider.create(bytes, parent, name);
            if (cf != null)
              return cf;
          }
        }
    } catch(Throwable t) {
      return javaClassFile;
    }

    return javaClassFile;
  }

  IBuffer around(ClassFile cf, SourceMapper mapper, IBinaryType info, IClassFile owner) :
    mapSource(cf, mapper, info, owner) {
    return mapSourceSubst(cf, mapper, info);
  }

  IBuffer around(ClassFile cf, SourceMapper mapper, IBinaryType info) :
    mapSource2(cf, mapper, info) {
    return mapSourceSubst(cf, mapper, info);
  }

  IBuffer mapSourceSubst(ClassFile cf, SourceMapper mapper, IBinaryType info) {
    char[] contents = mapper.findSource(cf.getType(), info);
    IBuffer buffer;
    if (contents != null) {
      buffer = BufferManager.createBuffer(cf);
      buffer.setContents(contents);
    } else {
      buffer = BufferManager.createNullBuffer(cf);
    }
    BufferManager bufManager = cf.getBufferManager();
    bufManager.addBuffer(buffer);
    buffer.addBufferChangedListener(cf);
    return buffer;
  }

  String around(ClassFile cf) :
    getTypeName(cf) {
    if(cf instanceof IScalaClassFile) {
      int lastDollar = cf.name.lastIndexOf('$');
      return (lastDollar == -1 || lastDollar == cf.name.length()-1) ? cf.name : Util.localTypeName(cf.name, lastDollar, cf.name.length());
    } else
      return proceed(cf);
  }

  boolean around(Viewer viewer, Object parentElement, Object element) :
    select(viewer, parentElement, element) {
    if (element instanceof IScalaClassFile) {
      IClassFile classFile = (IClassFile) element;
      String name = classFile.getElementName();
      int dollarIndex = name.indexOf('$');
      return dollarIndex == -1 || dollarIndex == name.length()-7; // Trailing '$' implies object rather than inner class
    }
    return proceed(viewer, parentElement, element);
  }

  IJavaElement[] around(BinaryType bt) throws JavaModelException :
    getChildren(bt) &&
    target(BinaryType) {
    ClassFile cf = (ClassFile)bt.parent;
    if (cf instanceof IScalaClassFile)
      return cf.getChildren();
    else
      return proceed(bt);
  }

  CompilationUnit around(ITypeRoot element, SharedASTProvider.WAIT_FLAG waitFlag, IProgressMonitor progressMonitor) :
    getAST(element, waitFlag, progressMonitor) {
      if (element instanceof IScalaElement)
        return null;
      else
        return proceed(element, waitFlag, progressMonitor);
  }

  void around(HierarchyResolver hr, IGenericType suppliedType) :
    resolve(hr, suppliedType) {
    if (!suppliedType.isBinaryType()) {
      IType tpe = ((SourceTypeElementInfo)suppliedType).getHandle();
      IClassFile cf = tpe.getClassFile();
      if (cf instanceof IScalaClassFile) {
        hr.resolve(new Openable[]{(Openable)cf}, new HashSet(), null);
        return;
      }
    }

    proceed(hr, suppliedType);
  }

  String around(BinaryType bt) :
    getSourceFileName(bt) {
    IJavaElement parent = bt.getTypeRoot();
    if (parent instanceof IScalaClassFile) {
      return ((IScalaClassFile)parent).getSourceFileName();
    }
    else
      return proceed(bt);
  }

  boolean around(IType type, int acceptFlags, boolean isSourceType) :
    acceptType(type, acceptFlags, isSourceType) {
    if (!isSourceType && (type instanceof SourceType)) {
      IJavaElement parent = type.getParent();
      if (parent instanceof IScalaClassFile)
        return proceed(type, acceptFlags, true);
    }

    return proceed(type, acceptFlags, isSourceType);
  }

  CompilationUnitDeclaration around(SourceTypeConverter stc, ISourceType[] sourceTypes, CompilationResult compilationResult) throws JavaModelException :
    convert(stc, sourceTypes, compilationResult) {
    stc.unit = new CompilationUnitDeclaration(stc.problemReporter, compilationResult, 0);
    // not filled at this point

    if (sourceTypes.length == 0 || sourceTypes[0] == null) return stc.unit;
    SourceTypeElementInfo topLevelTypeInfo = (SourceTypeElementInfo) sourceTypes[0];
    org.eclipse.jdt.core.ICompilationUnit cuHandle = topLevelTypeInfo.getHandle().getCompilationUnit();
    stc.cu = (ICompilationUnit) cuHandle;

    CompilationUnitElementInfo cuei = null;
    Object info = ((JavaElement)stc.cu).getElementInfo();
    if (info instanceof CompilationUnitElementInfo)
      cuei = (CompilationUnitElementInfo)info;

    if (stc.has1_5Compliance && cuei != null && cuei.annotationNumber > 10) { // experimental value
      // if more than 10 annotations, diet parse as this is faster
      return new Parser(stc.problemReporter, true).dietParse(stc.cu, compilationResult);
    }

    /* only positions available */
    int start = topLevelTypeInfo.getNameSourceStart();
    int end = topLevelTypeInfo.getNameSourceEnd();

    /* convert package and imports */
    String[] packageName = ((PackageFragment) cuHandle.getParent()).names;
    if (packageName.length > 0)
      // if its null then it is defined in the default package
      stc.unit.currentPackage =
        stc.createImportReference(packageName, start, end, false, ClassFileConstants.AccDefault);
    IImportDeclaration[] importDeclarations = topLevelTypeInfo.getHandle().getCompilationUnit().getImports();
    int importCount = importDeclarations.length;
    stc.unit.imports = new ImportReference[importCount];
    for (int i = 0; i < importCount; i++) {
      ImportDeclaration importDeclaration = (ImportDeclaration) importDeclarations[i];
      ISourceImport sourceImport = (ISourceImport) importDeclaration.getElementInfo();
      String nameWithoutStar = importDeclaration.getNameWithoutStar();
      stc.unit.imports[i] = stc.createImportReference(
        Util.splitOn('.', nameWithoutStar, 0, nameWithoutStar.length()),
        sourceImport.getDeclarationSourceStart(),
        sourceImport.getDeclarationSourceEnd(),
        importDeclaration.isOnDemand(),
        sourceImport.getModifiers());
    }
    /* convert type(s) */
    try {
      int typeCount = sourceTypes.length;
      final TypeDeclaration[] types = new TypeDeclaration[typeCount];
      /*
       * We used a temporary types collection to prevent this.unit.types from being null during a call to
       * convert(...) when the source is syntactically incorrect and the parser is flushing the unit's types.
       * See https://bugs.eclipse.org/bugs/show_bug.cgi?id=97466
       */
      for (int i = 0; i < typeCount; i++) {
        SourceTypeElementInfo typeInfo = (SourceTypeElementInfo) sourceTypes[i];
        types[i] = stc.convert((SourceType) typeInfo.getHandle(), compilationResult);
      }
      stc.unit.types = types;
      return stc.unit;
    } catch (SourceTypeConverter.AnonymousMemberFound e) {
      return new Parser(stc.problemReporter, true).parse(stc.cu, compilationResult);
    }
  }

  IJavaElement around(JavaElement je, int ancestorType) :
    getAncestor(je, ancestorType) {
    IJavaElement element = je;
    while (element != null) {
      if (element.getElementType() == ancestorType)
        return element;
      else if (element instanceof IScalaClassFile && ancestorType == IJavaElement.COMPILATION_UNIT)
        return ((JavaElement)element).getCompilationUnit();
      element= element.getParent();
    }
    return null;
  }

  boolean around(TypeNameMatch match) :
    isContainerDirty(match) {
    org.eclipse.jdt.core.ICompilationUnit cu = match.getType().getCompilationUnit();
    if (cu == null) {
      return false;
    }
    IResource resource= cu.getResource();
    if (resource == null)
      return false;

    ITextFileBufferManager manager= FileBuffers.getTextFileBufferManager();
    ITextFileBuffer textFileBuffer= manager.getTextFileBuffer(resource.getFullPath(), LocationKind.IFILE);
    if (textFileBuffer != null) {
      return textFileBuffer.isDirty();
    }
    return false;
  }
}

/*
 * Copyright 2005-2010 LAMP/EPFL
 */
// $Id$

package scala.tools.eclipse.contribution.weaving.jdt.cfprovider;

import java.util.HashSet;

import org.eclipse.core.filebuffers.FileBuffers;
import org.eclipse.core.filebuffers.ITextFileBuffer;
import org.eclipse.core.filebuffers.ITextFileBufferManager;
import org.eclipse.core.filebuffers.LocationKind;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.jdt.core.IBuffer;
import org.eclipse.jdt.core.IClassFile;
import org.eclipse.jdt.core.IImportDeclaration;
import org.eclipse.jdt.core.IJavaElement;
import org.eclipse.jdt.core.IOpenable;
import org.eclipse.jdt.core.IType;
import org.eclipse.jdt.core.ITypeRoot;
import org.eclipse.jdt.core.JavaModelException;
import org.eclipse.jdt.core.dom.CompilationUnit;
import org.eclipse.jdt.core.search.TypeNameMatch;
import org.eclipse.jdt.internal.compiler.CompilationResult;
import org.eclipse.jdt.internal.compiler.ast.ASTNode;
import org.eclipse.jdt.internal.compiler.ast.CompilationUnitDeclaration;
import org.eclipse.jdt.internal.compiler.ast.ImportReference;
import org.eclipse.jdt.internal.compiler.ast.TypeDeclaration;
import org.eclipse.jdt.internal.compiler.ast.TypeReference;
import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants;
import org.eclipse.jdt.internal.compiler.env.IBinaryType;
import org.eclipse.jdt.internal.compiler.env.ICompilationUnit;
import org.eclipse.jdt.internal.compiler.env.IGenericType;
import org.eclipse.jdt.internal.compiler.env.ISourceImport;
import org.eclipse.jdt.internal.compiler.env.ISourceType;
import org.eclipse.jdt.internal.compiler.env.NameEnvironmentAnswer;
import org.eclipse.jdt.internal.compiler.lookup.ReferenceBinding;
import org.eclipse.jdt.internal.compiler.lookup.SourceTypeBinding;
import org.eclipse.jdt.internal.compiler.parser.Parser;
import org.eclipse.jdt.internal.compiler.parser.SourceTypeConverter;
import org.eclipse.jdt.internal.core.BinaryType;
import org.eclipse.jdt.internal.core.ClassFile;
import org.eclipse.jdt.internal.core.CompilationUnitElementInfo;
import org.eclipse.jdt.internal.core.ImportDeclaration;
import org.eclipse.jdt.internal.core.JavaElement;
import org.eclipse.jdt.internal.core.BufferManager;
import org.eclipse.jdt.internal.core.NameLookup;
import org.eclipse.jdt.internal.core.Openable;
import org.eclipse.jdt.internal.core.PackageFragment;
import org.eclipse.jdt.internal.core.SearchableEnvironment;
import org.eclipse.jdt.internal.core.SourceMapper;
import org.eclipse.jdt.internal.core.SourceType;
import org.eclipse.jdt.internal.core.SourceTypeElementInfo;
import org.eclipse.jdt.internal.core.hierarchy.HierarchyResolver;
import org.eclipse.jdt.internal.core.hierarchy.HierarchyType;
import org.eclipse.jdt.internal.core.util.Util;
import org.eclipse.jdt.internal.corext.util.OpenTypeHistory;
import org.eclipse.jdt.internal.ui.filters.InnerClassFilesFilter;
import org.eclipse.jdt.ui.SharedASTProvider;
import org.eclipse.jface.viewers.Viewer;

import scala.tools.eclipse.contribution.weaving.jdt.IScalaClassFile;
import scala.tools.eclipse.contribution.weaving.jdt.IScalaElement;

@SuppressWarnings("restriction")
public privileged aspect ClassFileProviderAspect {

  pointcut classFileCreations(PackageFragment parent, String name) :
    call(protected ClassFile.new(PackageFragment, String)) &&
    within(org.eclipse.jdt..*) &&
    args(parent, name);

  pointcut getTypeName(ClassFile cf) :
    execution(public String ClassFile.getTypeName()) &&
    target(cf);

  // For 3.6
  pointcut mapSource(ClassFile cf, SourceMapper mapper, IBinaryType info, IClassFile owner) :
    execution(IBuffer ClassFile.mapSource(SourceMapper, IBinaryType, IClassFile)) &&
    target(cf) &&
    target(IScalaClassFile) &&
    args(mapper, info, owner);

  // For 3.5
  pointcut mapSource2(ClassFile cf, SourceMapper mapper, IBinaryType info) :
    execution(IBuffer ClassFile.mapSource(SourceMapper, IBinaryType)) &&
    target(cf) &&
    target(IScalaClassFile) &&
    args(mapper, info);

  pointcut getSourceFileName(BinaryType bt) :
    execution(String BinaryType.getSourceFileName(IBinaryType)) &&
    target(bt);

  pointcut select(Viewer viewer, Object parentElement, Object element) :
    execution(boolean InnerClassFilesFilter.select(Viewer, Object, Object)) &&
    args(viewer, parentElement, element);

  pointcut getChildren(BinaryType bt) :
    execution(IJavaElement[] BinaryType.getChildren()) &&
    target(bt);

  pointcut getAST(ITypeRoot element, SharedASTProvider.WAIT_FLAG waitFlag, IProgressMonitor progressMonitor) :
    execution(CompilationUnit SharedASTProvider.getAST(ITypeRoot, SharedASTProvider.WAIT_FLAG, IProgressMonitor)) &&
    args(element, waitFlag, progressMonitor);

  pointcut resolve(HierarchyResolver hr, IGenericType suppliedType) :
    execution(void HierarchyResolver.resolve(IGenericType)) &&
    target(hr) &&
    args(suppliedType);

  pointcut remember(HierarchyResolver hr, IType type, ReferenceBinding typeBinding) :
    execution(void HierarchyResolver.remember(IType, ReferenceBinding)) &&
    target(hr) &&
    args(type, typeBinding);

  pointcut acceptType(IType type, int acceptFlags, boolean isSourceType) :
    execution(boolean NameLookup.acceptType(IType, int, boolean)) &&
    args(type, acceptFlags, isSourceType);

  pointcut find(SearchableEnvironment se, String typeName, String packageName) :
    execution(NameEnvironmentAnswer find(String, String)) &&
    target(se) &&
    args(typeName, packageName);

  pointcut convert(SourceTypeConverter stc, ISourceType[] sourceTypes, CompilationResult compilationResult) :
    execution(CompilationUnitDeclaration SourceTypeConverter.convert(ISourceType[], CompilationResult)) &&
    target(stc) &&
    args(sourceTypes, compilationResult);

  pointcut getAncestor(JavaElement je, int ancestorType) :
    execution(IJavaElement JavaElement.getAncestor(int)) &&
    target(je) &&
    args(ancestorType);

  pointcut isContainerDirty(TypeNameMatch match) :
    execution(boolean OpenTypeHistory.isContainerDirty(TypeNameMatch)) &&
    args(match);

  ClassFile around(PackageFragment parent, String name) :
    classFileCreations(parent, name) {

    ClassFile javaClassFile = proceed(parent, name);
    byte[] bytes;

    try {
        for (IClassFileProvider provider : ClassFileProviderRegistry.getInstance().getProviders()) {
          if (provider.isInteresting(javaClassFile)) {
            bytes = javaClassFile.getBytes();
            ClassFile cf = provider.create(bytes, parent, name);
            if (cf != null)
              return cf;
          }
        }
    } catch(Throwable t) {
      return javaClassFile;
    }

    return javaClassFile;
  }

  IBuffer around(ClassFile cf, SourceMapper mapper, IBinaryType info, IClassFile owner) :
    mapSource(cf, mapper, info, owner) {
    return mapSourceSubst(cf, mapper, info);
  }

  IBuffer around(ClassFile cf, SourceMapper mapper, IBinaryType info) :
    mapSource2(cf, mapper, info) {
    return mapSourceSubst(cf, mapper, info);
  }

  IBuffer mapSourceSubst(ClassFile cf, SourceMapper mapper, IBinaryType info) {
    char[] contents = mapper.findSource(cf.getType(), info);
    IBuffer buffer;
    if (contents != null) {
      buffer = BufferManager.createBuffer(cf);
      buffer.setContents(contents);
    } else {
      buffer = BufferManager.createNullBuffer(cf);
    }
    BufferManager bufManager = cf.getBufferManager();
    bufManager.addBuffer(buffer);
    buffer.addBufferChangedListener(cf);
    return buffer;
  }

  String around(ClassFile cf) :
    getTypeName(cf) {
    if(cf instanceof IScalaClassFile) {
      int lastDollar = cf.name.lastIndexOf('$');
      return (lastDollar == -1 || lastDollar == cf.name.length()-1) ? cf.name : Util.localTypeName(cf.name, lastDollar, cf.name.length());
    } else
      return proceed(cf);
  }

  boolean around(Viewer viewer, Object parentElement, Object element) :
    select(viewer, parentElement, element) {
    if (element instanceof IScalaClassFile) {
      IClassFile classFile = (IClassFile) element;
      String name = classFile.getElementName();
      int dollarIndex = name.indexOf('$');
      return dollarIndex == -1 || dollarIndex == name.length()-7; // Trailing '$' implies object rather than inner class
    }
    return proceed(viewer, parentElement, element);
  }

  IJavaElement[] around(BinaryType bt) throws JavaModelException :
    getChildren(bt) &&
    target(BinaryType) {
    ClassFile cf = (ClassFile)bt.parent;
    if (cf instanceof IScalaClassFile)
      return cf.getChildren();
    else
      return proceed(bt);
  }

  CompilationUnit around(ITypeRoot element, SharedASTProvider.WAIT_FLAG waitFlag, IProgressMonitor progressMonitor) :
    getAST(element, waitFlag, progressMonitor) {
      if (element instanceof IScalaElement)
        return null;
      else
        return proceed(element, waitFlag, progressMonitor);
  }

  void around(HierarchyResolver hr, IGenericType suppliedType) :
    resolve(hr, suppliedType) {
    if (!suppliedType.isBinaryType()) {
      IType tpe = ((SourceTypeElementInfo)suppliedType).getHandle();
      IClassFile cf = tpe.getClassFile();
      if (cf instanceof IScalaClassFile) {
        hr.resolve(new Openable[]{(Openable)cf}, new HashSet(), null);
        return;
      }
    }

    proceed(hr, suppliedType);
  }

  void around(HierarchyResolver hr, IType type, ReferenceBinding typeBinding) :
    remember(hr, type, typeBinding) {
    if (((IOpenable)type.getCompilationUnit()).isOpen()) {
      try {
        IGenericType genericType = (IGenericType)((JavaElement)type).getElementInfo();
        hr.remember(genericType, typeBinding);
      } catch (JavaModelException e) {
        // cannot happen since element is open
        return;
      }
    } else {
      if (typeBinding == null) return;

      TypeDeclaration typeDeclaration = ((SourceTypeBinding)typeBinding).scope.referenceType();

      // simple super class name
      char[] superclassName = null;
      TypeReference superclass;
      boolean anonymous;
      if ((typeDeclaration.bits & ASTNode.IsAnonymousType) != 0) {
        superclass = typeDeclaration.allocation.type;
        anonymous = true;
      } else {
        superclass = typeDeclaration.superclass;
        anonymous = false;
      }
      if (superclass != null) {
        char[][] typeName = superclass.getTypeName();
        superclassName = typeName == null ? null : typeName[typeName.length-1];
      }

      // simple super interface names
      char[][] superInterfaceNames = null;
      TypeReference[] superInterfaces = typeDeclaration.superInterfaces;
      if (superInterfaces != null) {
        int length = superInterfaces.length;
        superInterfaceNames = new char[length][];
        for (int i = 0; i < length; i++) {
          TypeReference superInterface = superInterfaces[i];
          char[][] typeName = superInterface.getTypeName();
          superInterfaceNames[i] = typeName[typeName.length-1];
        }
      }

      HierarchyType hierarchyType = new HierarchyType(
        type,
        typeDeclaration.name,
        typeDeclaration.binding.modifiers,
        superclassName,
        superInterfaceNames,
        anonymous);
      hr.remember(hierarchyType, typeDeclaration.binding);
    }
  }

  String around(BinaryType bt) :
    getSourceFileName(bt) {
    IJavaElement parent = bt.getTypeRoot();
    if (parent instanceof IScalaClassFile) {
      return ((IScalaClassFile)parent).getSourceFileName();
    }
    else
      return proceed(bt);
  }

  boolean around(IType type, int acceptFlags, boolean isSourceType) :
    acceptType(type, acceptFlags, isSourceType) {
    if (!isSourceType && (type instanceof SourceType)) {
      IJavaElement parent = type.getParent();
      if (parent instanceof IScalaClassFile)
        return proceed(type, acceptFlags, true);
    }

    return proceed(type, acceptFlags, isSourceType);
  }

  CompilationUnitDeclaration around(SourceTypeConverter stc, ISourceType[] sourceTypes, CompilationResult compilationResult) throws JavaModelException :
    convert(stc, sourceTypes, compilationResult) {
    stc.unit = new CompilationUnitDeclaration(stc.problemReporter, compilationResult, 0);
    // not filled at this point

    if (sourceTypes.length == 0 || sourceTypes[0] == null) return stc.unit;
    SourceTypeElementInfo topLevelTypeInfo = (SourceTypeElementInfo) sourceTypes[0];
    org.eclipse.jdt.core.ICompilationUnit cuHandle = topLevelTypeInfo.getHandle().getCompilationUnit();
    stc.cu = (ICompilationUnit) cuHandle;

    CompilationUnitElementInfo cuei = null;
    Object info = ((JavaElement)stc.cu).getElementInfo();
    if (info instanceof CompilationUnitElementInfo)
      cuei = (CompilationUnitElementInfo)info;

    if (stc.has1_5Compliance && cuei != null && cuei.annotationNumber > 10) { // experimental value
      // if more than 10 annotations, diet parse as this is faster
      return new Parser(stc.problemReporter, true).dietParse(stc.cu, compilationResult);
    }

    /* only positions available */
    int start = topLevelTypeInfo.getNameSourceStart();
    int end = topLevelTypeInfo.getNameSourceEnd();

    /* convert package and imports */
    String[] packageName = ((PackageFragment) cuHandle.getParent()).names;
    if (packageName.length > 0)
      // if its null then it is defined in the default package
      stc.unit.currentPackage =
        stc.createImportReference(packageName, start, end, false, ClassFileConstants.AccDefault);
    IImportDeclaration[] importDeclarations = topLevelTypeInfo.getHandle().getCompilationUnit().getImports();
    int importCount = importDeclarations.length;
    stc.unit.imports = new ImportReference[importCount];
    for (int i = 0; i < importCount; i++) {
      ImportDeclaration importDeclaration = (ImportDeclaration) importDeclarations[i];
      ISourceImport sourceImport = (ISourceImport) importDeclaration.getElementInfo();
      String nameWithoutStar = importDeclaration.getNameWithoutStar();
      stc.unit.imports[i] = stc.createImportReference(
        Util.splitOn('.', nameWithoutStar, 0, nameWithoutStar.length()),
        sourceImport.getDeclarationSourceStart(),
        sourceImport.getDeclarationSourceEnd(),
        importDeclaration.isOnDemand(),
        sourceImport.getModifiers());
    }
    /* convert type(s) */
    try {
      int typeCount = sourceTypes.length;
      final TypeDeclaration[] types = new TypeDeclaration[typeCount];
      /*
       * We used a temporary types collection to prevent this.unit.types from being null during a call to
       * convert(...) when the source is syntactically incorrect and the parser is flushing the unit's types.
       * See https://bugs.eclipse.org/bugs/show_bug.cgi?id=97466
       */
      for (int i = 0; i < typeCount; i++) {
        SourceTypeElementInfo typeInfo = (SourceTypeElementInfo) sourceTypes[i];
        types[i] = stc.convert((SourceType) typeInfo.getHandle(), compilationResult);
      }
      stc.unit.types = types;
      return stc.unit;
    } catch (SourceTypeConverter.AnonymousMemberFound e) {
      return new Parser(stc.problemReporter, true).parse(stc.cu, compilationResult);
    }
  }

  IJavaElement around(JavaElement je, int ancestorType) :
    getAncestor(je, ancestorType) {
    IJavaElement element = je;
    while (element != null) {
      if (element.getElementType() == ancestorType)
        return element;
      else if (element instanceof IScalaClassFile && ancestorType == IJavaElement.COMPILATION_UNIT)
        return ((JavaElement)element).getCompilationUnit();
      element= element.getParent();
    }
    return null;
  }

  boolean around(TypeNameMatch match) :
    isContainerDirty(match) {
    org.eclipse.jdt.core.ICompilationUnit cu = match.getType().getCompilationUnit();
    if (cu == null) {
      return false;
    }
    IResource resource= cu.getResource();
    if (resource == null)
      return false;

    ITextFileBufferManager manager= FileBuffers.getTextFileBufferManager();
    ITextFileBuffer textFileBuffer= manager.getTextFileBuffer(resource.getFullPath(), LocationKind.IFILE);
    if (textFileBuffer != null) {
      return textFileBuffer.isDirty();
    }
    return false;
  }
}


add ConcurrentHashMap

add ConcurrentHashMap

/*
 * hashshmash - An aspect to record HashMap/Set allocations
 * Copyright 2013 MeBigFatGuy.com
 * Copyright 2013 Dave Brosius
 *
 * 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 com.mebigfatguy.hashshmash;

import java.io.BufferedWriter;
import java.io.File;
import java.io.FileOutputStream;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.lang.reflect.Field;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;

public aspect HashCollector {

    private static final Journaller journaller = new Journaller();

    after() returning (Map<?,?> m): call(HashMap.new(..)) {
        String fileName = thisJoinPointStaticPart.getSourceLocation().getFileName();
        int line = thisJoinPointStaticPart.getSourceLocation().getLine();

        HashMapDetails details = new HashMapDetails(m, new Date(), fileName + ":" + line);
        journaller.add(details);
    }

    after() returning (Map<?,?> m): call(LinkedHashMap.new(..)) {
        String fileName = thisJoinPointStaticPart.getSourceLocation().getFileName();
        int line = thisJoinPointStaticPart.getSourceLocation().getLine();

        HashMapDetails details = new LinkedHashMapDetails(m, new Date(), fileName + ":" + line);
        journaller.add(details);
    }

    after() returning (Map<?,?> m): call(ConcurrentHashMapMap.new(..)) {
        String fileName = thisJoinPointStaticPart.getSourceLocation().getFileName();
        int line = thisJoinPointStaticPart.getSourceLocation().getLine();

        HashMapDetails details = new ConcurrentHashMapDetails(m, new Date(), fileName + ":" + line);
        journaller.add(details);
    }

    after() returning (Set<?> s): call(HashSet.new(..)) {
        String fileName = thisJoinPointStaticPart.getSourceLocation().getFileName();
        int line = thisJoinPointStaticPart.getSourceLocation().getLine();

        HashSetDetails details = new HashSetDetails(s, new Date(), fileName + ":" + line);
        journaller.add(details);
    }

    after() returning (Set<?> s): call(LinkedHashSet.new(..)) {
        String fileName = thisJoinPointStaticPart.getSourceLocation().getFileName();
        int line = thisJoinPointStaticPart.getSourceLocation().getLine();

        HashSetDetails details = new LinkedHashSetDetails(s, new Date(), fileName + ":" + line);
        journaller.add(details);
    }

    before(): execution(public static void *.main(String[])) {
        Class<?> c = HashCollector.class;
    }
}

final class Journaller implements Runnable {

    private static final int SLEEP_TIME = 5 * 1000;

    private Field tableField;
    private ConcurrentHashMap<HashDetails, HashDetails> hDetails = new ConcurrentHashMap<HashDetails, HashDetails>();
    private PrintWriter writer;
    private boolean operational = false;

    public Journaller() {
        try {
            System.out.println("*************************");
            System.out.println("HASHSHMASH ASPECT ENABLED");
            System.out.println("*************************");

            tableField = HashMap.class.getDeclaredField("table");
            tableField.setAccessible(true);

            File dir = new File(System.getProperty("user.home"), ".hashshmash");
            dir.mkdirs();

            writer = new PrintWriter(new BufferedWriter(new OutputStreamWriter(new FileOutputStream(new File(dir, new Date().toString() + ".txt")))));

            Thread t = new Thread(this);
            t.setDaemon(true);
            operational = true;
            t.start();
        } catch (Exception e) {
        }
    }

    public void add(HashDetails details) {
        if (operational)
            hDetails.put(details,  details);
    }

    public void run() {
        try {
            while (!Thread.interrupted()) {
                Thread.sleep(SLEEP_TIME);

                for (HashDetails details : hDetails.keySet()) {
                    try {
                        Map<?, ?> map = details.getMap();
                        if (map != null) {
                            int newSize = details.getMap().size();
                            if (newSize == details.size) {
                                Entry<?, ?>[] table = (Entry<?, ?>[])tableField.get(map);
                                details.totalSlots = table.length;
                                for (Entry<?, ?> e : table) {
                                    if (e != null) {
                                        details.usedSlots++;
                                    }
                                }
                                writer.println(details);
                                hDetails.remove(details);
                            } else
                                details.size = newSize;
                        } else {
                            hDetails.remove(details);
                        }
                    } catch (Exception e) {
                        //might get ConcurrentModificationException or such, just ignore
                    }
                }
                writer.flush();
            }
        } catch (InterruptedException ie) {
        }
    }
}

abstract class HashDetails {
    private static SimpleDateFormat FORMATTER = new SimpleDateFormat("MM/dd/yyyy HH:mm:ss-SSS");

    public Date allocTime;
    public String caller;
    public int size;
    public int usedSlots;
    public int totalSlots;

    public abstract Map<?,?> getMap();

    public abstract String getDetailType();

    public String toString() {
        return getDetailType() + "\t" + FORMATTER.format(allocTime) + "\t" + caller + "\t" + getMap().size() + "\t" + totalSlots + "\t" + usedSlots;
    }
}

class HashMapDetails extends HashDetails {
    public Map<?, ?> map;

    public HashMapDetails(Map<?, ?> m, Date d, String c) {
        map = m;
        allocTime = d;
        caller = c;
        size = map.size();
    }

    public Map<?,?> getMap() {
        return map;
    }

    public String getDetailType() {
        return map.getClass().getSimpleName();
    }
}

class LinkedHashMapDetails extends HashMapDetails {
    public Map<?, ?> map;

    public LinkedHashMapDetails(Map<?, ?> m, Date d, String c) {
       super(m, d, c);
    }

    public String getDetailType() {
        return map.getClass().getSimpleName();
    }
}

class ConcurrentHashMapDetails extends HashMapDetails {
    public Map<?, ?> map;

        public ConcurrentHashMapDetails(Map<?, ?> m, Date d, String c) {
           super(m, d, c);
        }

        public String getDetailType() {
            return map.getClass().getSimpleName();
        }
}

class HashSetDetails extends HashDetails {
    private static Field MAP_FIELD;
    static {
        try {
            MAP_FIELD = HashSet.class.getDeclaredField("map");
            MAP_FIELD.setAccessible(true);
        } catch (Exception e) {
            MAP_FIELD = null;
        }
    }

    public Set<?> set;

    public HashSetDetails(Set<?> s, Date d, String c) {
        set = s;
        allocTime = d;
        caller = c;
        size = set.size();
    }

    public Map<?,?> getMap() {
        try {
            if (MAP_FIELD == null)
                return null;

            return (Map<?,?>) MAP_FIELD.get(set);
        } catch (Exception e) {
            return null;
        }
    }

    public String getDetailType() {
        return set.getClass().getSimpleName();
    }
}

class LinkedHashSetDetails extends HashSetDetails {
    public Map<?, ?> map;

    public LinkedHashSetDetails(Set<?> s, Date d, String c) {
       super(s, d, c);
    }

    public String getDetailType() {
        return map.getClass().getSimpleName();
    }
}

/*
 * hashshmash - An aspect to record HashMap/Set allocations
 * Copyright 2013 MeBigFatGuy.com
 * Copyright 2013 Dave Brosius
 *
 * 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 com.mebigfatguy.hashshmash;

import java.io.BufferedWriter;
import java.io.File;
import java.io.FileOutputStream;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.lang.reflect.Field;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;

public aspect HashCollector {

    private static final Journaller journaller = new Journaller();

    after() returning (Map<?,?> m): call(HashMap.new(..)) {
        String fileName = thisJoinPointStaticPart.getSourceLocation().getFileName();
        int line = thisJoinPointStaticPart.getSourceLocation().getLine();

        HashMapDetails details = new HashMapDetails(m, new Date(), fileName + ":" + line);
        journaller.add(details);
    }

    after() returning (Map<?,?> m): call(LinkedHashMap.new(..)) {
        String fileName = thisJoinPointStaticPart.getSourceLocation().getFileName();
        int line = thisJoinPointStaticPart.getSourceLocation().getLine();

        HashMapDetails details = new LinkedHashMapDetails(m, new Date(), fileName + ":" + line);
        journaller.add(details);
    }

    after() returning (Set<?> s): call(HashSet.new(..)) {
        String fileName = thisJoinPointStaticPart.getSourceLocation().getFileName();
        int line = thisJoinPointStaticPart.getSourceLocation().getLine();

        HashSetDetails details = new HashSetDetails(s, new Date(), fileName + ":" + line);
        journaller.add(details);
    }

    after() returning (Set<?> s): call(LinkedHashSet.new(..)) {
        String fileName = thisJoinPointStaticPart.getSourceLocation().getFileName();
        int line = thisJoinPointStaticPart.getSourceLocation().getLine();

        HashSetDetails details = new LinkedHashSetDetails(s, new Date(), fileName + ":" + line);
        journaller.add(details);
    }

    before(): execution(public static void *.main(String[])) {
        Class<?> c = HashCollector.class;
    }
}

final class Journaller implements Runnable {

    private static final int SLEEP_TIME = 5 * 1000;

    private Field tableField;
    private ConcurrentHashMap<HashDetails, HashDetails> hDetails = new ConcurrentHashMap<HashDetails, HashDetails>();
    private PrintWriter writer;
    private boolean operational = false;

    public Journaller() {
        try {
            System.out.println("*************************");
            System.out.println("HASHSHMASH ASPECT ENABLED");
            System.out.println("*************************");

            tableField = HashMap.class.getDeclaredField("table");
            tableField.setAccessible(true);

            File dir = new File(System.getProperty("user.home"), ".hashshmash");
            dir.mkdirs();

            writer = new PrintWriter(new BufferedWriter(new OutputStreamWriter(new FileOutputStream(new File(dir, new Date().toString() + ".txt")))));

            Thread t = new Thread(this);
            t.setDaemon(true);
            operational = true;
            t.start();
        } catch (Exception e) {
        }
    }

    public void add(HashDetails details) {
        if (operational)
            hDetails.put(details,  details);
    }

    public void run() {
        try {
            while (!Thread.interrupted()) {
                Thread.sleep(SLEEP_TIME);

                for (HashDetails details : hDetails.keySet()) {
                    try {
                        Map<?, ?> map = details.getMap();
                        if (map != null) {
                            int newSize = details.getMap().size();
                            if (newSize == details.size) {
                                Entry<?, ?>[] table = (Entry<?, ?>[])tableField.get(map);
                                details.totalSlots = table.length;
                                for (Entry<?, ?> e : table) {
                                    if (e != null) {
                                        details.usedSlots++;
                                    }
                                }
                                writer.println(details);
                                hDetails.remove(details);
                            } else
                                details.size = newSize;
                        } else {
                            hDetails.remove(details);
                        }
                    } catch (Exception e) {
                        //might get ConcurrentModificationException or such, just ignore
                    }
                }
                writer.flush();
            }
        } catch (InterruptedException ie) {
        }
    }
}

abstract class HashDetails {
    private static SimpleDateFormat FORMATTER = new SimpleDateFormat("MM/dd/yyyy HH:mm:ss-SSS");

    public Date allocTime;
    public String caller;
    public int size;
    public int usedSlots;
    public int totalSlots;

    public abstract Map<?,?> getMap();

    public abstract String getDetailType();

    public String toString() {
        return getDetailType() + "\t" + FORMATTER.format(allocTime) + "\t" + caller + "\t" + getMap().size() + "\t" + totalSlots + "\t" + usedSlots;
    }
}

class HashMapDetails extends HashDetails {
    public Map<?, ?> map;

    public HashMapDetails(Map<?, ?> m, Date d, String c) {
        map = m;
        allocTime = d;
        caller = c;
        size = map.size();
    }

    public Map<?,?> getMap() {
        return map;
    }

    public String getDetailType() {
        return map.getClass().getSimpleName();
    }
}

class LinkedHashMapDetails extends HashMapDetails {
    public Map<?, ?> map;

    public LinkedHashMapDetails(Map<?, ?> m, Date d, String c) {
       super(m, d, c);
    }

    public String getDetailType() {
        return map.getClass().getSimpleName();
    }
}

class HashSetDetails extends HashDetails {
    private static Field MAP_FIELD;
    static {
        try {
            MAP_FIELD = HashSet.class.getDeclaredField("map");
            MAP_FIELD.setAccessible(true);
        } catch (Exception e) {
            MAP_FIELD = null;
        }
    }

    public Set<?> set;

    public HashSetDetails(Set<?> s, Date d, String c) {
        set = s;
        allocTime = d;
        caller = c;
        size = set.size();
    }

    public Map<?,?> getMap() {
        try {
            if (MAP_FIELD == null)
                return null;

            return (Map<?,?>) MAP_FIELD.get(set);
        } catch (Exception e) {
            return null;
        }
    }

    public String getDetailType() {
        return set.getClass().getSimpleName();
    }
}

class LinkedHashSetDetails extends HashSetDetails {
    public Map<?, ?> map;

    public LinkedHashSetDetails(Set<?> s, Date d, String c) {
       super(s, d, c);
    }

    public String getDetailType() {
        return map.getClass().getSimpleName();
    }
}