All Downloads are FREE. Search and download functionalities are using the official Maven repository.

io.ebean.enhance.transactional.ScopeTransAdapter Maven / Gradle / Ivy

There is a newer version: 15.10.0
Show newest version
package io.ebean.enhance.transactional;

import io.ebean.enhance.asm.AnnotationVisitor;
import io.ebean.enhance.asm.Label;
import io.ebean.enhance.asm.MethodVisitor;
import io.ebean.enhance.asm.Opcodes;
import io.ebean.enhance.asm.Type;
import io.ebean.enhance.asm.commons.FinallyAdapter;
import io.ebean.enhance.common.AnnotationInfo;
import io.ebean.enhance.common.AnnotationInfoVisitor;
import io.ebean.enhance.common.EnhanceConstants;
import io.ebean.enhance.common.VisitUtil;

import java.util.ArrayList;

/**
 * Adapts a method to support Transactional.
 * 

* Adds a TxScope and ScopeTrans local variables. On normal exit makes a call * out via InternalServer to end the scopeTrans depending on the exit type * opcode (ATHROW vs ARETURN etc) and whether particular throwable's cause a * rollback or not. *

*/ public class ScopeTransAdapter extends FinallyAdapter implements EnhanceConstants { private static final Type txScopeType = Type.getType("L"+C_TXSCOPE+";"); private static final Type helpScopeTrans = Type.getType(L_HELPSCOPETRANS); private final AnnotationInfo annotationInfo; private final ClassAdapterTransactional owner; private final String methodName; private boolean transactional; private int posTxScope; private int lineNumber; private TransactionalMethodKey methodKey; ScopeTransAdapter(ClassAdapterTransactional owner, final MethodVisitor mv, final int access, final String name, final String desc) { super(Opcodes.ASM5, mv, access, name, desc); this.owner = owner; this.methodName = name; // inherit from class level Transactional annotation AnnotationInfo parentInfo = owner.getClassAnnotationInfo(); // inherit from interface method transactional annotation AnnotationInfo interfaceInfo = owner.getInterfaceTransactionalInfo(name, desc); if (parentInfo == null){ parentInfo = interfaceInfo; } else { parentInfo.setParent(interfaceInfo); } // inherit transactional annotations from parentInfo annotationInfo = new AnnotationInfo(parentInfo); // default based on whether Transactional annotation // is at the class level or on interface method transactional = parentInfo != null; } @Override public void visitLineNumber(int line, Label start) { super.visitLineNumber(line, start); if (lineNumber == 0 && methodKey != null) { lineNumber = line; methodKey.setLineNumber(lineNumber); } } @Override public AnnotationVisitor visitAnnotation(String desc, boolean visible) { AnnotationVisitor av = super.visitAnnotation(desc, visible); if (desc.equals(AVAJE_TRANSACTIONAL_ANNOTATION)) { transactional = true; return new AnnotationInfoVisitor(null, annotationInfo, av); } else { return av; } } private void setTxType(Object txType){ mv.visitVarInsn(ALOAD, posTxScope); mv.visitLdcInsn(txType.toString()); mv.visitMethodInsn(INVOKESTATIC, C_TXTYPE, "valueOf", "(Ljava/lang/String;)L"+C_TXTYPE+";", false); mv.visitMethodInsn(INVOKEVIRTUAL, C_TXSCOPE, "setType", "(L"+C_TXTYPE+";)L"+C_TXSCOPE+";", false); mv.visitInsn(POP); } private void setTxIsolation(Object txIsolation){ mv.visitVarInsn(ALOAD, posTxScope); mv.visitLdcInsn(txIsolation.toString()); mv.visitMethodInsn(INVOKESTATIC, C_TXISOLATION, "valueOf", "(Ljava/lang/String;)L"+C_TXISOLATION+";", false); mv.visitMethodInsn(INVOKEVIRTUAL, C_TXSCOPE, "setIsolation", "(L"+C_TXISOLATION+";)L"+C_TXSCOPE+";", false); mv.visitInsn(POP); } private void setBatch(Object batch){ mv.visitVarInsn(ALOAD, posTxScope); mv.visitLdcInsn(batch.toString()); mv.visitMethodInsn(INVOKESTATIC, C_PERSISTBATCH, "valueOf", "(Ljava/lang/String;)L"+C_PERSISTBATCH+";", false); mv.visitMethodInsn(INVOKEVIRTUAL, C_TXSCOPE, "setBatch", "(L"+C_PERSISTBATCH+";)L"+C_TXSCOPE+";", false); mv.visitInsn(POP); } private void setBatchOnCascade(Object batch){ mv.visitVarInsn(ALOAD, posTxScope); mv.visitLdcInsn(batch.toString()); mv.visitMethodInsn(INVOKESTATIC, C_PERSISTBATCH, "valueOf", "(Ljava/lang/String;)L"+C_PERSISTBATCH+";", false); mv.visitMethodInsn(INVOKEVIRTUAL, C_TXSCOPE, "setBatchOnCascade", "(L"+C_PERSISTBATCH+";)L"+C_TXSCOPE+";", false); mv.visitInsn(POP); } private void setProfileId(int profileId){ mv.visitVarInsn(ALOAD, posTxScope); VisitUtil.visitIntInsn(mv, profileId); mv.visitMethodInsn(INVOKEVIRTUAL, C_TXSCOPE, "setProfileId", "(I)L"+C_TXSCOPE+";", false); mv.visitInsn(POP); } private void setBatchSize(Object batchSize){ mv.visitVarInsn(ALOAD, posTxScope); VisitUtil.visitIntInsn(mv, Integer.parseInt(batchSize.toString())); mv.visitMethodInsn(INVOKEVIRTUAL, C_TXSCOPE, "setBatchSize", "(I)L"+C_TXSCOPE+";", false); mv.visitInsn(POP); } private void setGetGeneratedKeys(Object getGeneratedKeys){ boolean getKeys = (Boolean)getGeneratedKeys; if (!getKeys) { mv.visitVarInsn(ALOAD, posTxScope); mv.visitMethodInsn(INVOKEVIRTUAL, C_TXSCOPE, "setSkipGeneratedKeys", "()L"+C_TXSCOPE+";", false); } } private void setReadOnly(Object readOnlyObj){ boolean readOnly = (Boolean)readOnlyObj; mv.visitVarInsn(ALOAD, posTxScope); if (readOnly){ mv.visitInsn(ICONST_1); } else { mv.visitInsn(ICONST_0); } mv.visitMethodInsn(INVOKEVIRTUAL, C_TXSCOPE, "setReadOnly", "(Z)L"+C_TXSCOPE+";", false); } private void setFlushOnQuery(Object flushObj){ boolean flushOnQuery = (Boolean)flushObj; if (!flushOnQuery){ mv.visitVarInsn(ALOAD, posTxScope); mv.visitInsn(ICONST_0); mv.visitMethodInsn(INVOKEVIRTUAL, C_TXSCOPE, "setFlushOnQuery", "(Z)L"+C_TXSCOPE+";", false); } } /** * Add bytecode to add the noRollbackFor throwable types to the TxScope. */ private void setNoRollbackFor(Object noRollbackFor){ ArrayList list = (ArrayList)noRollbackFor; for (Object aList : list) { Type throwType = (Type) aList; mv.visitVarInsn(ALOAD, posTxScope); mv.visitLdcInsn(throwType); mv.visitMethodInsn(INVOKEVIRTUAL, txScopeType.getInternalName(), "setNoRollbackFor", "(Ljava/lang/Class;)L" + C_TXSCOPE + ";", false); mv.visitInsn(POP); } } /** * Add bytecode to add the rollbackFor throwable types to the TxScope. */ private void setRollbackFor(Object rollbackFor){ ArrayList list = (ArrayList)rollbackFor; for (Object aList : list) { Type throwType = (Type) aList; mv.visitVarInsn(ALOAD, posTxScope); mv.visitLdcInsn(throwType); mv.visitMethodInsn(INVOKEVIRTUAL, txScopeType.getInternalName(), "setRollbackFor", "(Ljava/lang/Class;)L" + C_TXSCOPE + ";", false); mv.visitInsn(POP); } } /** * Return the profileId from the transactional annotation. */ private int annotationProfileId() { Object value = annotationInfo.getValue("profileId"); if (value == null) { return 0; } else { return (int)value; } } @Override protected void onMethodEnter() { if (!transactional) { return; } methodKey = owner.createMethodKey(methodName, methodDesc, annotationProfileId()); posTxScope = newLocal(txScopeType); mv.visitTypeInsn(NEW, txScopeType.getInternalName()); mv.visitInsn(DUP); mv.visitMethodInsn(INVOKESPECIAL, txScopeType.getInternalName(), "", "()V", false); mv.visitVarInsn(ASTORE, posTxScope); Object txType = annotationInfo.getValue("type"); if (txType != null){ setTxType(txType); } int profileId = methodKey.getProfileId(); if (profileId > 0) { setProfileId(profileId); } Object txIsolation = annotationInfo.getValue("isolation"); if (txIsolation != null){ setTxIsolation(txIsolation); } Object batch = annotationInfo.getValue("batch"); if (batch != null){ setBatch(batch); } Object batchOnCascade = annotationInfo.getValue("batchOnCascade"); if (batchOnCascade != null){ setBatchOnCascade(batchOnCascade); } Object batchSize = annotationInfo.getValue("batchSize"); if (batchSize != null){ setBatchSize(batchSize); } Object getGeneratedKeys = annotationInfo.getValue("getGeneratedKeys"); if (getGeneratedKeys != null){ setGetGeneratedKeys(getGeneratedKeys); } Object readOnly = annotationInfo.getValue("readOnly"); if (readOnly != null){ setReadOnly(readOnly); } Object flushOnQuery = annotationInfo.getValue("flushOnQuery"); if (flushOnQuery != null){ setFlushOnQuery(flushOnQuery); } Object noRollbackFor = annotationInfo.getValue("noRollbackFor"); if (noRollbackFor != null){ setNoRollbackFor(noRollbackFor); } Object rollbackFor = annotationInfo.getValue("rollbackFor"); if (rollbackFor != null){ setRollbackFor(rollbackFor); } mv.visitVarInsn(ALOAD, posTxScope); mv.visitMethodInsn(INVOKESTATIC, helpScopeTrans.getInternalName(), "enter", "(" + txScopeType.getDescriptor() + ")V", false); } @Override protected void onFinally(int opcode) { if (!transactional) { return; } owner.transactionalMethod(methodKey); if (opcode == RETURN) { visitInsn(ACONST_NULL); } else if (opcode == ARETURN || opcode == ATHROW) { dup(); } else { if (opcode == LRETURN || opcode == DRETURN) { dup2(); } else { dup(); } box(Type.getReturnType(this.methodDesc)); } visitIntInsn(SIPUSH, opcode); visitMethodInsn(INVOKESTATIC, helpScopeTrans.getInternalName(), "exit", "(Ljava/lang/Object;I)V", false); } }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy