com.sun.jdo.api.persistence.enhancer.impl.ClassControl Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of payara-micro Show documentation
Show all versions of payara-micro Show documentation
Micro Distribution of the Payara Project
/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
*
* Copyright (c) 1997-2010 Oracle and/or its affiliates. All rights reserved.
*
* The contents of this file are subject to the terms of either the GNU
* General Public License Version 2 only ("GPL") or the Common Development
* and Distribution License("CDDL") (collectively, the "License"). You
* may not use this file except in compliance with the License. You can
* obtain a copy of the License at
* https://glassfish.dev.java.net/public/CDDL+GPL_1_1.html
* or packager/legal/LICENSE.txt. See the License for the specific
* language governing permissions and limitations under the License.
*
* When distributing the software, include this License Header Notice in each
* file and include the License file at packager/legal/LICENSE.txt.
*
* GPL Classpath Exception:
* Oracle designates this particular file as subject to the "Classpath"
* exception as provided by Oracle in the GPL Version 2 section of the License
* file that accompanied this code.
*
* Modifications:
* If applicable, add the following below the License Header, with the fields
* enclosed by brackets [] replaced by your own identifying information:
* "Portions Copyright [year] [name of copyright owner]"
*
* Contributor(s):
* If you wish your version of this file to be governed by only the CDDL or
* only the GPL Version 2, indicate your decision by adding "[Contributor]
* elects to include this software in this distribution under the [CDDL or GPL
* Version 2] license." If you don't indicate a single choice of license, a
* recipient has the option to distribute your version of this file under
* either the CDDL, the GPL Version 2 or to extend the choice of license to
* its licensees as provided above. However, if you add GPL Version 2 code
* and therefore, elected the GPL Version 2 license, then the option applies
* only if the new code is made subject to such option by the copyright
* holder.
*/
package com.sun.jdo.api.persistence.enhancer.impl;
import java.io.*;
import java.util.Map;
import java.util.Hashtable;
import java.util.Iterator;
import com.sun.jdo.api.persistence.enhancer.classfile.ClassFile;
import com.sun.jdo.api.persistence.enhancer.classfile.ClassField;
import com.sun.jdo.api.persistence.enhancer.classfile.ClassMethod;
import com.sun.jdo.api.persistence.enhancer.classfile.ConstClass;
import com.sun.jdo.api.persistence.enhancer.util.Support;
import com.sun.jdo.api.persistence.enhancer.util.UserException;
import com.sun.jdo.api.persistence.enhancer.util.ClassFileSource;
//@olsen: added import
import com.sun.jdo.api.persistence.enhancer.meta.JDOMetaData;
//@olsen: cosmetics
//@olsen: moved: this class -> package impl
//@olsen: subst: [iI]Persistent -> [pP]ersistenceCapable
//@olsen: subst: jdo/ -> com/sun/forte4j/persistence/internal/
//@olsen: subst: /* ... */ -> // ...
//@olsen: subst: filterEnv -> env
//@olsen: subst: FilterEnv -> Environment
//@olsen: dropped parameter 'Environment env', use association instead
//@olsen: subst: Hashtable -> Map, HashMap
//@olsen: subst: Enumeration,... -> Iterator, hasNext(), next()
//@olsen: subst: absolut jdo types and names -> constants from JDOMetaData
//@olsen: subst: persistType() -> persistenceType
//@olsen: subst: ClassControl. ->
//@olsen: added: support for I18N
//@olsen: subst: FilterError -> UserException, affirm()
//@olsen: removed: support for [No]AnnotateField
//@olsen: removed: old, disabled ODI code
/**
* ClassControl acts as the primary handle for a class within the
* filter tool. ClassControl instances are typically accessed through
* various methods on Environment.
*/
public final class ClassControl
extends Support {
/* Valid persistence types */
/* The user didn't tell us to make this persistence-capable or
* persistence-aware and it doesn't appear to be annotated */
//@olsen: changed value 3 -> -1
static public final int TransientOnly = -1;
/* The user made no explicit statement about the persistence capability. */
static public final int PersistUnknown = 0;
/* The user said that this class needs to be annotated for fetch/dirty
* but the class doesn't need to be stored persistently */
//@olsen: changed value 2 -> 1
static public final int PersistAware = 1;
/* The user said this class should be persistence capable or it was
* promoted to persistence-capable status as a result of being a base
* class of an explicitly persistence capable class */
//@olsen: changed value 1 -> 2
static public final int PersistCapable = 2;
/* A filtered version of this class exists and is up to date w.r.t.
* the unfiltered versionr - filtering will NOT be required.
*/
//@olsen: changed value 3 -> -1
static public final int UpdateNotNeeded = -1;
/* It is not yet known whether the current filtered version of this
* class exists or if it is up-to-date w.r.t. the unfiltered version.
*/
static public final int UpdateUnknown = 0;
/* No filtered version of this class exists - filtering will be required.
*/
static public final int UpdateNew = 1;
/* A filtered version of this class exists but the unfiltered version
* is newer - filtering will be required.
*/
static public final int UpdateNewer = 2;
/* Central repository for the options and classes */
//@olsen: added association
//@olsen: made final
private final Environment env;
/* The class to be annotated */
//@olsen: made final
private final ClassFileSource theClassSource;
/* The classfile to be annotated */
private ClassFile theClass;
/* What type of class is this w.r.t. persistence */
private int persistenceType = PersistUnknown;
/* What type of class is this w.r.t. persistence as defined on cmd line */
//@olsen: disabled feature
/*
private int initialPersistenceType = PersistUnknown;
*/
/* Was this class promoted to persistent capable? */
//@olsen: disabled feature
/*
private boolean implicitlyPersistent = false;
*/
/* Was this class explicitly listed on the command line? */
//@olsen: disabled feature
/*
private boolean explicitlyMentioned = false;
*/
/* What is the update state of the class */
private int updateType = UpdateUnknown;
/* What annotation related actions are to be performed for the class */
//@olsen: made final
private final ClassAction classAction;
/* If true, this class is believed to have been modified in some way */
private boolean classUpdated;
/* If true, this class was renamed via repackaging */
//@olsen: disabled feature
/*
private boolean classRenamed;
*/
// public accessors
/**
* Return true if the classfile has been updated
*/
public boolean updated() {
return classUpdated;
}
/**
* Return true if the classfile has been renamed
*/
//@olsen: disabled feature
/*
public boolean renamed() {
return classRenamed;
}
*/
/**
* Record a modification of the class
*/
public void noteUpdate() {
classUpdated = true;
}
/**
* Get the ClassFile data structure for the class
*/
public ClassFile classFile() {
return theClass;
}
/**
* Return the persistence type for this class
*/
public int persistType() {
return persistenceType;
}
/**
* Return the initial persistence type for this class
*/
//@olsen: disabled feature
/*
public int initialPersistType() {
return initialPersistenceType;
}
*/
/**
* Return true if the persistence type for this class is either
* PersistAware or PersistCapable.
*/
//@olsen: not used
//@olsen: disabled feature
/*
public boolean persistAware() {
if (persistenceType == PersistUnknown)
checkPersistAware();
return (persistenceType == PersistCapable ||
persistenceType == PersistAware);
}
*/
/**
* Return true if the persistence type for this class is PersistCapable.
*/
//@olsen: disabled feature
/*
public boolean persistCapable() {
if (persistenceType == PersistUnknown)
checkPersistAware();
return persistenceType == PersistCapable;
}
*/
/**
* Return true if filtering of the class is required.
* This checks only whether the filtered version of the class is
* up to date w.r.t. its input class.
*/
public boolean filterRequired() {
if (updateType == UpdateUnknown)
checkUpdateType();
//@olsen: optimized code
return (updateType > UpdateUnknown || env.forceOverwrite());
/*
return (updateType == UpdateNew
|| updateType == UpdateNewer
|| env.forceOverwrite());
*/
}
/**
* Mark the class as requiring update.
*/
public void requireUpdate() {
updateType = UpdateNew;
}
/**
* Return true if the class is one which should be a candidate for
* annotation.
*/
public boolean annotateable() {
//@olsen: disabled feature: isImplicitlyPersistent()
/*
return (initialPersistenceType == PersistCapable ||
initialPersistenceType == PersistAware ||
isImplicitlyPersistent());
*/
//@olsen: changed to check each class not explicitly known as transient
return (persistenceType >= PersistUnknown);
}
/**
* Set the peristence type for this class
*/
//@olsen: disabled feature: -> setPersistenceType()
/*
public void setPersistType(int ptype) {
persistenceType = ptype;
}
*/
/**
* Set the initial peristence type for this class
*/
//@olsen: disabled feature
/*
public void setInitialPersistType(int ptype) {
initialPersistenceType = ptype;
persistenceType = ptype;
}
*/
/**
* Returns true if this class was promoted to persistent implicitly
*/
//@olsen: disabled feature
/*
public boolean isImplicitlyPersistent() {
return implicitlyPersistent;
}
*/
/**
* Record that this class was promoted to persistence capable
*/
//@olsen: disabled feature
/*
public void setImplicitlyPersistent(boolean wasPromoted) {
implicitlyPersistent = wasPromoted;
}
*/
/**
* Returns true if this class was explicitly named on the command line
*/
//@olsen: disabled feature
/*
public boolean isExplicitlyNamed() {
return explicitlyMentioned;
}
*/
/**
* Record whether this class was explicitly listed as a class on the
* command line.
*/
//@olsen: disabled feature
/*
public void setExplicitlyNamed(boolean wasNamed) {
explicitlyMentioned = wasNamed;
}
*/
/**
* Get the ClassAction for this class
*/
public ClassAction action() {
return classAction;
}
/**
* Constructor
*/
//@olsen: added parameter 'env' for association
public ClassControl(ClassFileSource theSource,
Environment env) {
theClassSource = theSource;
buildTheClass(true /* allowJDK12ClassFiles */);
theClassSource.setExpectedClassName(className());
classAction = new ClassAction(this, env);
this.env = env;
if (false) {
System.out.println("ClassControl(): new class = " + className());//NOI18N
}
}
/**
* Constructor
*/
//@olsen: added parameter 'env' for association
public ClassControl(ClassFileSource theSource,
ClassFile theFile,
Environment env) {
theClassSource = theSource;
theClass = theFile;
theClassSource.setExpectedClassName(className());
classAction = new ClassAction(this, env);
this.env = env;
if (false) {
System.out.println("ClassControl(): new class = " + className());//NOI18N
}
}
/**
* Sets the persistence type of a class by JDO meta-data.
*/
//@olsen: added method
private void setPersistenceType() {
final JDOMetaData meta = env.getJDOMetaData();
//@olsen: skip class if its persistence type is already known
if (persistenceType != PersistUnknown) {
return;
}
//@olsen: check whether class is an interface
if (classFile().isInterface()) {
persistenceType = TransientOnly;
return;
}
//@olsen: check whether class is known to be transient
final String className = className();
if (meta.isTransientClass(className)) {
persistenceType = TransientOnly;
return;
}
//@olsen: check whether class is persistence-capable
if (meta.isPersistenceCapableClass(className)) {
persistenceType = PersistCapable;
//@olsen: for Dogwood, check limitation on PC-inheritance
affirm(meta.isPersistenceCapableRootClass(className),
("Sorry, not supported yet: the persistent-capable class "//NOI18N
+ userClassName()
+ "cannot extend a persistent-capable super-class."));//NOI18N
}
}
/**
* Note the class characteristics
*/
public void scan1() {
//@olsen: added support for timing statistics
try{
if (env.doTimingStatistics()) {
Support.timer.push("ClassControl.scan1()");//NOI18N
}
//@olsen: added: set the persistent type of class
setPersistenceType();
//@olsen: disabled feature
/*
if (annotateable() || implementsPersistenceCapable()) {
*/
if (annotateable()) {
//@olsen: dropped argument: boolean filterRequired
//classAction.scan1(filterRequired());
if (filterRequired()) {
classAction.scan1();
} else {
//@olsen: added output
env.message("skipping " + userClassName() + //NOI18N
" because it is already up to date.");//NOI18N
}
}
} finally {
if (env.doTimingStatistics()) {
Support.timer.pop();
}
}
}
/**
* Check the class to see what actions need to be performed
*/
//@olsen: disabled feature
/*
public void scan2() {
if (annotateable()) {
env.message("computing annotations for " + userClassName());
classAction.scan2(filterRequired());
}
}
*/
/**
* Reparent class if needed
*/
//@olsen: subst: augmentInterfaces -> augment
public void augment() {
//@olsen: added support for timing statistics
try{
if (env.doTimingStatistics()) {
Support.timer.push("ClassControl.augment()");//NOI18N
}
if (annotateable()) {
//@olsen: dropped argument: boolean filterRequired
//classAction.augment(filterRequired());
if (filterRequired()) {
classAction.augment();
} else {
//@olsen: added output
env.message("skipping " + userClassName() + //NOI18N
" because it is already up to date.");//NOI18N
}
}
} finally {
if (env.doTimingStatistics()) {
Support.timer.pop();
}
}
}
/**
* Retarget the class if needed
*/
//@olsen: disabled feature
/*
public void retarget(Map classTranslations) {
// Trust our caller on this one
// The check for filterRequired is pushed down into ClassAction
// for this method to allow any special considerations to be made
// there.
if (classTranslations.get(className()) != null)
classRenamed = true;
env.message("retargetting class references for " + userClassName());
classAction.retarget(classTranslations,
filterRequired());
// update our class source to reflect our new name if it has changed
// We need to do this even if filtering is not required
theClassSource.setExpectedClassName(className());
}
*/
/**
* perform necessary annotation actions on the class
*/
public void annotate() {
//@olsen: added support for timing statistics
try{
if (env.doTimingStatistics()) {
Support.timer.push("ClassControl.annotate()");//NOI18N
}
if (annotateable()) {
if (filterRequired()) {
classAction.annotate();
} else {
env.message("skipping " + userClassName() + //NOI18N
" because it is already up to date.");//NOI18N
}
}
} finally {
if (env.doTimingStatistics()) {
Support.timer.pop();
}
}
}
// package accessors
/**
* Return the class name in VM form
*/
public String className() {
ConstClass cname = theClass.className();
return (cname == null) ? null : cname.asString();
}
/**
* Return the class name in user ('.' delimited) form
*/
public String userClassName() {
return userClassFromVMClass(className());
}
/**
* Return the class name in user ('.' delimited) form
*/
//^olsen: move to -> classfile.Descriptor ?
static public String userClassFromVMClass(String vmName) {
return vmName.replace('/', '.');
}
/**
* Return the class name in VM ('/' delimited) form
*/
//^olsen: move to -> classfile.Descriptor ?
static public String vmClassFromUserClass(String userName) {
return userName.replace('.', '/');
}
/**
* Return the vm package name for this class
*/
public String pkg() {
return packageOf(className());
}
/**
* Return the vm package name for the vm class name
*/
static public String packageOf(String vmName) {
int last = vmName.lastIndexOf('/');
if (last < 0)
return "";//NOI18N
return vmName.substring(0, last);
}
/**
* Return the unpackaged name for this class
*/
//@olsen: disabled feature
/*
public String unpackagedName() {
return unpackagedNameOf(className());
}
*/
/**
* Return the unpackaged name for the vm class name
*/
//@olsen: disabled feature
/*
static public String unpackagedNameOf(String vmName) {
int last = vmName.lastIndexOf('/');
if (last < 0)
return vmName;
return vmName.substring(last+1);
}
*/
/**
* Return the name of the class source
*/
public String sourceName() {
return theClassSource.containingFilePath();
}
/**
* Return the source of the class
*/
public ClassFileSource source() {
return theClassSource;
}
/**
* Check whether the class already implements PersistenceCapable.
* Drag in new classes if needed.
*/
//@olsen: disabled feature
/*
public boolean implementsPersistenceCapable() {
return implementsInterface(JDOMetaData.JDOPersistenceCapablePath,
null);
}
*/
//@olsen: disabled feature
/*
abstract class Checker {
abstract boolean checkClass(ClassControl aClass);
}
*/
/**
* Check whether the class will implement PersistenceCapableHooks
* in the absence of the postprocessor doing it.
* Drag in new classes if needed. Must not be called until scan2 phase
*/
//@olsen: disabled feature
/*
public boolean hasPersistenceCapableHooksProvided() {
return implementsInterface(JDOMetaData.JDOInstanceCallbacksPath,
new Checker() {
boolean checkClass(ClassControl aClass) {
return (aClass != ClassControl.this &&
aClass.action().getImplementsPersistenceHooks());
}
});
}
*/
/**
* Check whether the class implements the specified class or
* is the specified class.
* If ccCheck is non-null, it is called on each ClassControl visited
* during the traversal to the base class as an additional predicate
* which, if it returns true, causes termination of the walk with
* a return value of true.
*
* TBD: modify this method and its callers to move all checking to
* the Checker predicate.
*/
//@olsen: disabled feature
/*
boolean implementsInterface(String implementClassName,
Checker ccChecker) {
String currClassName = className();
while (currClassName != null) {
ClassControl cc = env.findClass(currClassName);
if (cc == null)
return false;
ClassFile cf = cc.classFile();
Iterator interfaces = cf.interfaces().iterator();
while (interfaces.hasNext()) {
ConstClass i = (ConstClass)interfaces.next();
String interfaceName = i.asString();
ClassControl icc = env.findClass(interfaceName);
if (icc == null) {
env.error("Class " + interfaceName
+ " could not be found.");
return false;
}
if (interfaceName.equals(implementClassName) ||
icc.implementsInterface(implementClassName, ccChecker))
return true;
}
if (ccChecker != null && ccChecker.checkClass(cc))
return true;
ConstClass superClass = cf.superName();
if (superClass == null)
// java/lang/Object has no super class
return false;
currClassName = superClass.asString();
}
return false;
}
*/
/**
* Check whether the class derives from the specified class or
* is the specified class.
*/
//@olsen: disabled feature
/*
//@olsen: made public
public boolean inherits(String inheritClassName) {
String currClassName = className();
while (currClassName != null) {
if (currClassName.equals(inheritClassName))
return true;
ClassControl cc = env.findClass(currClassName);
if (cc == null)
return false;
ClassFile cf = cc.classFile();
ConstClass superClass = cf.superName();
if (superClass == null)
// java/lang/Object has no super class
return false;
currClassName = superClass.asString();
}
return false;
}
*/
/**
* Find the class which implements the given method and signature.
* Search up the class hierarchy from "this" until either java.lang.Object
* is found or a class which implements the method is found. Return
* null if the method has no implementation.
*/
//@olsen: disabled feature
/*
ClassControl findMethodClass(String methodName,
String methodSig) {
String currClassName = className();
while (currClassName != null) {
ClassControl cc = env.findClass(currClassName);
if (cc == null)
break;
ClassFile cf = cc.classFile();
if (cf.findMethod(methodName, methodSig) != null)
return cc;
ConstClass superClass = cf.superName();
if (superClass == null)
// java/lang/Object has no super class
return null;
currClassName = superClass.asString();
}
env.error("Class " + userClassFromVMClass(currClassName) +
" could not be found while trying to locate method " +
methodName);
return null;
}
*/
//@olsen: disabled feature -> get this information from JDOMetaData
/*
ClassControl findBasestPersistCapable() {
String currClassName = className();
ClassControl ret = null;
while (currClassName != null) {
ClassControl cc = env.findClass(currClassName);
if (cc == null)
break;
if (cc.persistCapable()) {
ret = cc;
}
ConstClass superClass = cc.classFile().superName();
if (superClass == null)
// java/lang/Object has no super class
return ret;
currClassName = superClass.asString();
}
env.error("Class " + userClassFromVMClass(currClassName) +
" could not be found while trying to locate Base class.");
return null;
}
*/
/**
* Write the file. If destination directory is non-null, write the
* file relative to that directory, else write it relative to its
* original location.
*/
//@olsen: made public
public void write(File destFile)
throws IOException, FileNotFoundException {
DataOutputStream dos =
theClassSource.getOutputStream(destFile);
theClass.write(dos);
dos.close();
}
// private methods
/**
* Check to see if this class appears to be annotated. If so,
* update PersistUnknown to PersistAware.
*/
//@olsen: disabled feature
/*
private void checkPersistAware() {
if (persistenceType == PersistUnknown) {
if (action().hasAnnotatedAttribute()) {
// The class is annotated - it is either
// persistence-aware or persistence-capable.
if (implementsPersistenceCapable())
persistenceType = PersistCapable;
else
persistenceType = PersistAware;
} else {
// Either unannotated or manually annotated.
// We used to check for the presence of a ClassInfo class
// but the fact that we are relying now on dynamic classinfo
// means that we encounter increasing numbers of false
// warnings so for now, we'll just assume that the
// PersistenceCapable is sufficient and defer error detection
// until runtime.
if (implementsPersistenceCapable()
|| classFile().isInterface())
persistenceType = PersistCapable;
// This code still needs to be implemented but not being
// implemented simply means that more array fetches might
// occur than are really necessary.
//else if (this class appears to be annotated)
// persistenceType = PersistAware;
else
persistenceType = TransientOnly;
}
}
}
*/
/**
* Check to see if output class for this class is up-to-date with
* respect to its input class. Set updateType to reflect what
* type of update of the output class is needed, if any.
*/
private void checkUpdateType() {
if (updateType == UpdateUnknown) {
String lookupName;
//@olsen: added inplace of disable featured
lookupName = className();
//@olsen: disabled feature
/*
// check to see if it exists in the updated form
String pkg = pkg();
String xlat = (String) env.translations().get(pkg);
if (xlat != null) {
if (xlat.length() == 0)
lookupName = unpackagedName();
else
lookupName = xlat + "/" + unpackagedName();
} else {
lookupName = className();
}
*/
ClassFileSource annotatedSource;
if (env.updateInPlace() && !theClassSource.isZipped())
annotatedSource = theClassSource;
else
annotatedSource = env.lookupDestClass(lookupName);
if (annotatedSource == null) {
// No annotated class exists
updateType = UpdateNew;
} else {
try {
long annModDate = annotatedSource.modificationDate();
long srcModDate = source().modificationDate();
if (annModDate < srcModDate) {
// An annotated class exists, but it is older than
// the input
updateType = UpdateNewer;
} else {
if (annotatedSource == theClassSource
&& !action().hasAnnotatedAttribute()) {
// An unannotated class file to be updated
// in-place
if (persistenceType == PersistCapable
|| persistenceType == PersistAware)
updateType = UpdateNewer;
else
updateType = UpdateNotNeeded;
} else {
//@olsen: an annotated class exists, which is
// newer than the input
updateType = UpdateNotNeeded;
}
}
} catch (FileNotFoundException e) {
// shouldn't occur, but if it does, handle it
updateType = UpdateNew;
}
}
}
}
/**
* Constructs the ClassFile for the class
*/
private void buildTheClass(boolean allowJDK12ClassFiles) {
if (false) {
System.out.println("Reading class "//NOI18N
+ theClassSource.expectedClassName());
}
//@olsen: cosmetics
//try {
// try {
// } catch (FileNotFoundException e) {
// }
//} catch (IOException e) {
//}
try {
DataInputStream dis = theClassSource.classFileContents();
theClass = new ClassFile(dis);
dis.close();
} catch (FileNotFoundException e) {
// File should already have been tested for existence
//@olsen: support for I18N
throw new UserException(
getI18N("enhancer.file_not_found",//NOI18N
sourceName()),
e);
} catch (IOException e) {
//@olsen: support for I18N
throw new UserException(
getI18N("enhancer.io_error_while_reading_file",//NOI18N
sourceName()),
e);
}
}
}