WALA/com.ibm.wala.j2ee/src/com/ibm/wala/j2ee/J2EEContainerModel.java

402 lines
15 KiB
Java

/*******************************************************************************
* Copyright (c) 2002 - 2006 IBM Corporation.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* IBM Corporation - initial API and implementation
*******************************************************************************/
package com.ibm.wala.j2ee;
import java.util.Collection;
import java.util.Collections;
import java.util.Iterator;
import java.util.Map;
import com.ibm.wala.classLoader.CallSiteReference;
import com.ibm.wala.classLoader.FieldImpl;
import com.ibm.wala.classLoader.IClass;
import com.ibm.wala.classLoader.IClassLoader;
import com.ibm.wala.classLoader.IField;
import com.ibm.wala.classLoader.IMethod;
import com.ibm.wala.classLoader.NewSiteReference;
import com.ibm.wala.classLoader.SyntheticClass;
import com.ibm.wala.ipa.cha.ClassHierarchy;
import com.ibm.wala.ipa.summaries.MethodSummary;
import com.ibm.wala.ipa.summaries.SummarizedMethod;
import com.ibm.wala.shrikeBT.BytecodeConstants;
import com.ibm.wala.shrikeBT.IInvokeInstruction;
import com.ibm.wala.shrikeCT.ClassConstants;
import com.ibm.wala.ssa.SSAInvokeInstruction;
import com.ibm.wala.ssa.SSANewInstruction;
import com.ibm.wala.ssa.SSAPutInstruction;
import com.ibm.wala.types.ClassLoaderReference;
import com.ibm.wala.types.Descriptor;
import com.ibm.wala.types.FieldReference;
import com.ibm.wala.types.MethodReference;
import com.ibm.wala.types.Selector;
import com.ibm.wala.types.TypeName;
import com.ibm.wala.types.TypeReference;
import com.ibm.wala.util.Atom;
import com.ibm.wala.util.collections.HashMapFactory;
import com.ibm.wala.util.collections.Iterator2Collection;
import com.ibm.wala.util.debug.Assertions;
/**
*
* A synthetic class that models aspects of the J2EE Container.
*
* @author Julian Dolby
* @author Stephen Fink
*/
class J2EEContainerModel extends SyntheticClass implements BytecodeConstants, EJBConstants {
private final static Atom syntheticLoaderName = Atom.findOrCreateUnicodeAtom("Synthetic");
private final static Atom extensionLoaderName = Atom.findOrCreateUnicodeAtom("Extension");
private final static ClassLoaderReference syntheticLoaderRef = new ClassLoaderReference(syntheticLoaderName);
private final static ClassLoaderReference extensionLoaderRef = new ClassLoaderReference(extensionLoaderName);
public static final TypeName containerModelName = TypeName.string2TypeName("L$ContainerModel");
public static final TypeName entityBeanName = TypeName.string2TypeName("Ljavax/ejb/EntityBean");
public static final TypeName entityContextName = TypeName.string2TypeName("Ljavax/ejb/EntityContext");
public static final TypeName sessionBeanName = TypeName.string2TypeName("Ljavax/ejb/SessionBean");
public static final TypeName sessionContextName = TypeName.string2TypeName("Ljavax/ejb/SessionContext");
public static final TypeName messageBeanName = TypeName.string2TypeName("Ljavax/ejb/MessageDrivenBean");
public static final TypeName messageContextName = TypeName.string2TypeName("Ljavax/ejb/MessageDrivenContext");
public static final TypeReference containerModelRef = TypeReference.findOrCreate(syntheticLoaderRef, containerModelName);
public static final TypeReference entityBeanRef = TypeReference.findOrCreate(extensionLoaderRef, entityBeanName);
public static final TypeReference entityContextRef = TypeReference.findOrCreate(extensionLoaderRef, entityContextName);
public static final TypeReference sessionBeanRef = TypeReference.findOrCreate(extensionLoaderRef, sessionBeanName);
public static final TypeReference sessionContextRef = TypeReference.findOrCreate(extensionLoaderRef, sessionContextName);
public static final TypeReference messageBeanRef = TypeReference.findOrCreate(extensionLoaderRef, messageBeanName);
public static final TypeReference messageContextRef = TypeReference.findOrCreate(extensionLoaderRef, messageContextName);
public static final Descriptor setEntityContextDescriptor = Descriptor.findOrCreate(new TypeName[] { entityContextName },
TypeReference.VoidName);
public static final Descriptor setSessionContextDescriptor = Descriptor.findOrCreate(new TypeName[] { sessionContextName },
TypeReference.VoidName);
public static final Descriptor setMessageContextDescriptor = Descriptor.findOrCreate(new TypeName[] { messageContextName },
TypeReference.VoidName);
public static final MethodReference setEntityContext = MethodReference.findOrCreate(entityBeanRef, Atom
.findOrCreateAsciiAtom("setEntityContext"), setEntityContextDescriptor);
public static final MethodReference setSessionContext = MethodReference.findOrCreate(sessionBeanRef, Atom
.findOrCreateAsciiAtom("setSessionContext"), setSessionContextDescriptor);
public static final MethodReference setMessageContext = MethodReference.findOrCreate(messageBeanRef, Atom
.findOrCreateAsciiAtom("setMessageDrivenContext"), setMessageContextDescriptor);
/**
* Governing deployment information
*/
private final DeploymentMetaData deployment;
/**
* Governing class hierarchy
*/
private final ClassHierarchy cha;
J2EEContainerModel(DeploymentMetaData deployment, ClassHierarchy cha) {
super(containerModelRef, cha);
this.cha = cha;
this.deployment = deployment;
initializeStaticFieldRefs();
}
public IClassLoader getClassLoader() {
return cha.getLoader(syntheticLoaderRef);
}
public IClass getSuperclass() {
return cha.lookupClass(TypeReference.JavaLangObject);
}
public Collection<IClass> getAllInterfaces() {
return Collections.emptyList();
}
public String getSourceFileName() {
return "This synthetic J2EE model class has no source source";
}
public Collection<IField> getDeclaredInstanceFields() {
return Collections.emptySet();
}
public Collection<IField> getAllInstanceFields() {
return Collections.emptySet();
}
public IMethod getMethod(Selector selector) {
if ((selector.getName() == MethodReference.clinitName) && (selector.getDescriptor().equals(MethodReference.defaultInitDesc)))
return getClassInitializer();
else
return null;
}
public Collection<IMethod> getDeclaredMethods() {
return Collections.singleton(getClassInitializer());
}
public String toString() {
return "<Synthetic J2EE Container Model>";
}
private Collection<FieldReference> staticFieldRefs = null;
private Map<Atom, IField> staticFieldMap = null;
/**
* Create a phony field name which logically holds a pointer to the one true
* instance of a given bean type
*/
public static Atom getBeanFieldName(TypeReference beanType) {
return getBeanFieldName(beanType.getName());
}
/**
* Create a phony field name which logically holds a pointer to the one true
* instance of a given bean type TODO: reconsider this atom generator ....
*/
public static Atom getBeanFieldName(TypeName beanTypeName) {
return Atom.findOrCreateUnicodeAtom("$$existing$" + beanTypeName.toString().replace('/', '$'));
}
/**
* Create a phony field reference which logically holds a pointer to the one
* true instance of a given bean type
*/
public static FieldReference getBeanFieldRef(TypeReference ejbType) {
return FieldReference.findOrCreate(containerModelRef, getBeanFieldName(ejbType), ejbType);
}
/**
* Create a phony field reference which logically holds a pointer to the one
* true instance of a given bean type
*/
public static FieldReference getBeanFieldRef(BeanMetaData bean) {
return getBeanFieldRef(bean.getEJBClass());
}
private void initializeStaticFieldRefs() {
final Iterator<BeanMetaData> entityBeans = deployment.iterateEntities();
final Iterator<BeanMetaData> sessionBeans = deployment.iterateSessions();
final Iterator<BeanMetaData> messageBeans = deployment.iterateMDBs();
Iterator<FieldReference> it = new Iterator<FieldReference>() {
public void remove() {
throw new UnsupportedOperationException();
}
public boolean hasNext() {
return entityBeans.hasNext() || sessionBeans.hasNext() || messageBeans.hasNext();
}
public FieldReference next() {
if (entityBeans.hasNext()) {
return getBeanFieldRef(entityBeans.next());
} else if (sessionBeans.hasNext()) {
return getBeanFieldRef(sessionBeans.next());
} else {
return getBeanFieldRef(messageBeans.next());
}
}
};
staticFieldRefs = new Iterator2Collection<FieldReference>(it);
initializeStaticFieldMap();
}
private void initializeStaticFieldMap() {
staticFieldMap = HashMapFactory.make();
for (Iterator<FieldReference> fs = staticFieldRefs.iterator(); fs.hasNext();) {
FieldReference f = fs.next();
staticFieldMap.put(f.getName(), new FieldImpl(this, f, ClassConstants.ACC_STATIC));
}
}
/*
* (non-Javadoc)
*
* @see com.ibm.wala.classLoader.IClass#getDeclaredStaticFields()
*/
public Collection<IField> getDeclaredStaticFields() {
return staticFieldMap.values();
}
public IField getField(Atom name) {
if (staticFieldMap == null) {
initializeStaticFieldMap();
}
return staticFieldMap.get(name);
}
private IMethod clinitMethod = null;
/**
* Create a <clinit> method for the synthetic container class
*
* @see com.ibm.wala.classLoader.IClass#getClassInitializer()
*/
public IMethod getClassInitializer() {
if (clinitMethod == null) {
MethodReference clinit = MethodReference.findOrCreate(containerModelRef, MethodReference.clinitName,
MethodReference.defaultInitDesc);
MethodSummary code = new MethodSummary(clinit);
code.setStatic(true);
int nextLocal = code.getNumberOfParameters() + 1;
Iterator<IField> fields = getDeclaredStaticFields().iterator();
while (fields.hasNext()) {
FieldReference field = fields.next().getFieldReference();
TypeReference ejbType = field.getFieldType();
// 1. create bean type representing pool objects
int beanAlloc = nextLocal++;
code.addStatement(new SSANewInstruction(beanAlloc, NewSiteReference.make(code.getNextProgramCounter(), ejbType)));
// 2. call set...Context, as required by lifecycle.
int contextAlloc = nextLocal++;
int ignoredExceptions = nextLocal++;
if (deployment.getBeanMetaData(ejbType).isSessionBean()) {
code.addStatement(new SSANewInstruction(contextAlloc, NewSiteReference.make(code.getNextProgramCounter(),
sessionContextRef)));
code.addStatement(new SSAInvokeInstruction(new int[] { beanAlloc, contextAlloc }, ignoredExceptions, CallSiteReference
.make(code.getNextProgramCounter(), setSessionContext, IInvokeInstruction.Dispatch.INTERFACE)));
} else if (deployment.getBeanMetaData(ejbType).isMessageDrivenBean()) {
code.addStatement(new SSANewInstruction(contextAlloc, NewSiteReference.make(code.getNextProgramCounter(),
messageContextRef)));
code.addStatement(new SSAInvokeInstruction(new int[] { beanAlloc, contextAlloc }, ignoredExceptions, CallSiteReference
.make(code.getNextProgramCounter(), setMessageContext, IInvokeInstruction.Dispatch.INTERFACE)));
// message driven beans also get ejbCreate called at this point
// (or that is how I interpret the spec, such as it is)
int moreIgnoredExceptions = nextLocal++;
MethodReference ejbCreate = MethodReference.findOrCreate(ejbType, EJB_CREATE, Descriptor.findOrCreate(null,
TypeReference.VoidName));
code.addStatement(new SSAInvokeInstruction(new int[] { beanAlloc }, moreIgnoredExceptions, CallSiteReference.make(code
.getNextProgramCounter(), ejbCreate, IInvokeInstruction.Dispatch.VIRTUAL)));
} else {
code.addStatement(new SSANewInstruction(contextAlloc, NewSiteReference.make(code.getNextProgramCounter(),
entityContextRef)));
code.addStatement(new SSAInvokeInstruction(new int[] { beanAlloc, contextAlloc }, ignoredExceptions, CallSiteReference
.make(code.getNextProgramCounter(), setEntityContext, IInvokeInstruction.Dispatch.INTERFACE)));
}
// 3. put bean into static field representing pool.
code.addStatement(new SSAPutInstruction(beanAlloc, field));
}
clinitMethod = new SummarizedMethod(clinit, code, this);
}
return clinitMethod;
}
/*
* (non-Javadoc)
*
* @see java.lang.Object#equals(java.lang.Object)
*/
public boolean equals(Object arg0) {
return arg0.getClass().equals(getClass());
}
/*
* (non-Javadoc)
*
* @see java.lang.Object#hashCode()
*/
public int hashCode() {
return 7;
}
/*
* (non-Javadoc)
*
* @see com.ibm.wala.classLoader.IClass#getModifiers()
*/
public int getModifiers() {
// TODO Auto-generated method stub
Assertions.UNREACHABLE();
return 0;
}
/*
* (non-Javadoc)
*
* @see com.ibm.wala.classLoader.IClass#getAllImplementedInterfaces()
*/
public Collection<IClass> getAllImplementedInterfaces() {
return Collections.emptySet();
}
/*
* (non-Javadoc)
*
* @see com.ibm.wala.classLoader.IClass#getAllAncestorInterfaces()
*/
public Collection<IClass> getAllAncestorInterfaces() {
// TODO Auto-generated method stub
Assertions.UNREACHABLE();
return null;
}
/*
* (non-Javadoc)
*
* @see com.ibm.wala.classLoader.IClass#getName()
*/
public TypeName getName() {
return getReference().getName();
}
/*
* (non-Javadoc)
*
* @see com.ibm.wala.classLoader.IClass#isReferenceType()
*/
public boolean isReferenceType() {
return getReference().isReferenceType();
}
/*
* (non-Javadoc)
*
* @see com.ibm.wala.classLoader.IClass#getDirectInterfaces()
*/
public Collection<IClass> getDirectInterfaces() {
// TODO Auto-generated method stub
Assertions.UNREACHABLE();
return null;
}
public Collection<IField> getAllStaticFields() {
return getDeclaredStaticFields();
}
public Collection<IField> getAllFields() {
return getDeclaredStaticFields();
}
public Collection<IMethod> getAllMethods() {
return Collections.singleton(getClassInitializer());
}
}