blob: be9495a66ca8d09ac8305ef8e20f8c5983a329fc [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2001, 2006 IBM Corporation and others.
* 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 org.eclipse.jst.j2ee.model.internal.validation;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.logging.Level;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.jobs.ISchedulingRule;
import org.eclipse.jem.java.JavaClass;
import org.eclipse.jem.util.logger.LogEntry;
import org.eclipse.jem.util.logger.proxy.Logger;
import org.eclipse.jst.j2ee.ejb.EJBJar;
import org.eclipse.jst.j2ee.ejb.EnterpriseBean;
import org.eclipse.jst.j2ee.ejb.Entity;
import org.eclipse.jst.j2ee.internal.J2EEConstants;
import org.eclipse.wst.validation.ValidationState;
import org.eclipse.wst.validation.internal.core.ValidationException;
import org.eclipse.wst.validation.internal.provisional.core.IMessage;
import org.eclipse.wst.validation.internal.provisional.core.IReporter;
import org.eclipse.wst.validation.internal.provisional.core.IValidationContext;
/**
* @version 1.0
* @author
*/
public class EJBValidator extends AbstractEJBValidator {
private static EJBValidator _inst = null;
private static TargetObjectPool _targetObjectPoolSingleton = null;
private LogEntry logEntry = null;
public EJBValidator() {
_inst = this;
}
public static EJBValidator getValidator() {
return _inst;
}
private LogEntry getLogEntry(){
if(logEntry == null)
logEntry = new LogEntry(IEJBValidatorConstants.BUNDLE_NAME);
return logEntry;
}
@Override
public String getBaseName() {
return "ejbvalidator"; //$NON-NLS-1$
}
public void commonValidate(IValidationContext helper, IReporter reporter) throws ValidationException {
long start = System.currentTimeMillis();
Logger logger = Logger.getLogger(IEJBValidatorConstants.J2EE_CORE_PLUGIN);
if (logger != null && logger.isLoggingLevel(Level.FINER)) {
long end = System.currentTimeMillis();
LogEntry entry = getLogEntry();
entry.setSourceID("EJBValidator::validate"); //$NON-NLS-1$
entry.setText("validate took " + (end - start) + " milliseconds."); //$NON-NLS-1$ //$NON-NLS-2$
logger.write(Level.FINER, entry);
}
try {
EJBValidationContext vc = new EJBValidationContext(this, helper, reporter);
setValidationContext(vc);
if (isFullValidate(vc)) {
fullValidate(vc);
} else {
incrementalValidate(vc);
}
if (logger != null && logger.isLoggingLevel(Level.FINER)) {
long end = System.currentTimeMillis();
LogEntry entry = getLogEntry();
entry.setSourceID("EJBValidator::validate"); //$NON-NLS-1$
entry.setText("validate took " + (end - start) + " milliseconds."); //$NON-NLS-1$ //$NON-NLS-2$
logger.write(Level.FINER, entry);
}
} finally {
}
}
@Override
public void validate(IValidationContext helper, IReporter reporter) throws ValidationException {
commonValidate(helper, reporter);
}
/*
* @see IValidator#validate(IValidationContext, IReporter, IFileDelta[])
*/
@Override
public IStatus validateInJob(IValidationContext helper, IReporter reporter) throws ValidationException {
commonValidate(helper, reporter);
return status;
}
public boolean isFullValidate(IEJBValidationContext vc) {
String[] fileURIs = vc.getURIs();
if(fileURIs == null) {
return true;
}
if(fileURIs.length == 0) {
return true;
}
for(int i=0; i<fileURIs.length; i++) {
String uri = fileURIs[i];
if(uri.endsWith(J2EEConstants.EJBJAR_DD_SHORT_NAME)) {
return true;
}
}
return false;
}
public void runDependents(IEJBValidationContext vc, IValidationRule rule, Object targetParent, Object target) throws ValidationException {
// If a class is being run only because it depends on a rule which has changed,
// i.e., it's a dependent, then we don't want to run its dependents because the
// class itself hasn't changed.
Set dependents = rule.getDependents();
if(dependents == null) {
return;
}
Iterator iterator = dependents.iterator();
while(iterator.hasNext()) {
try {
IValidationRule dRule = (IValidationRule)iterator.next();
Object dRuleTarget = dRule.getTarget(targetParent, target);
if(dRuleTarget != null) {
run(dRule, targetParent, dRuleTarget); // false=not full validation
}
}
catch(ValidationCancelledException e) {
throw e;
}
catch(ValidationException e) {
throw e;
}
catch(Throwable exc) {
addInternalErrorMessage(getValidationContext(), exc);
}
finally {
EJBValidationRuleFactory.getFactory().release(rule);
}
}
}
protected String internalErrorMessage() {
return IEJBValidatorMessageConstants.CHKJ2900;
}
@Override
protected void logMissingRule(IEJBValidationContext vc, Object ruleId) {
Logger logger = vc.getMsgLogger();
if (logger != null && logger.isLoggingLevel(Level.SEVERE)) {
logger.write(Level.SEVERE, ruleId + " = null"); //$NON-NLS-1$
}
addInternalErrorMessage(vc);
}
@Override
protected void preRemoveOldMessages(IEJBValidationContext vc, Map targets) throws ValidationException {
List validatedClasses = new ArrayList();
try {
String[] uris = vc.getURIs();
for(int i=0; i<uris.length; i++) {
String uriInst = uris[i];
if((uriInst == null) || (uriInst.length() == 0)) {
continue;
}
Object id = EJBValidationRuleFactory.getFactory().getRuleId(vc, uriInst);
if(id == null) {
Object[] clazzAndBean = (Object[])vc.loadModel(uriInst, null); // Don't need a second parameter, but can't cast a RefObject to an Object[], so use the second load method.
if(clazzAndBean == null) {
// Log, add "Cannot validate" to task list, and return.
logMissingRule(vc, id);
continue;
}
// In the clazzAndBean object array, the first entry is the JavaClass,
// and the rest of the entries are the EnterpriseBean instances which
// use the JavaClass.
JavaClass clazz = (JavaClass)clazzAndBean[0];
List beans = (List)clazzAndBean[1];
// The validatedClass set keeps track of JavaClasses
// that have changed, and this set is used to determine
// whose children need to be found and validated.
// Validation is performed after all of the changed files
// are validated so that all of the children of all of
// the changed files can be searched for at once. Searching
// once on a group produces performance savings because
// the type hierarchy method takes a non-trivial amount
// of time when there's a large group of deltas.
validatedClasses.add(clazz);
if((beans == null) || (beans.size() == 0)) {
// The JavaClass itself is not part of an enterprise bean, but one of its children may be.
}
else {
Iterator iterator = beans.iterator();
while(iterator.hasNext()) {
EnterpriseBean bean = (EnterpriseBean)iterator.next();
id = EJBValidationRuleFactory.getFactory().getRuleId(vc, clazz, bean);
IValidationRule clazzRule = EJBValidationRuleFactory.getFactory().getRule(vc, id);
if(clazzRule == null) {
// This has already been logged by the AbstractEJBValidationRuleFactory (if it's
// an error - this is expected if the key is a primitive primary key).
continue;
}
setValidated(clazzRule.getId(), bean, clazz);
}
}
}
else {
EJBJar ejbJar = (EJBJar)vc.loadModel(EJBValidatorModelEnum.EJB_MODEL);
if(ejbJar == null) {
// Log, add "Cannot validate" to task list, and return.
continue;
}
IValidationRule ejbExtRule = EJBValidationRuleFactory.getFactory().getRule(vc, id);
if(ejbExtRule == null) {
// This has already been logged by the AbstractEJBValidationRuleFactory, so just
// need to add "Cannot validate" to the task list.
continue;
}
setValidated(ejbExtRule.getId(), null, ejbJar);
}
} // end for
// Always validate ejb-jar.xml, because a change to one of the files it references
// may mean that it needs to be revalidated.
EJBJar ejbJar = (EJBJar)vc.loadModel(EJBValidatorModelEnum.EJB_MODEL);
if(ejbJar != null) {
Object id = EJBValidationRuleFactory.getFactory().getRuleId(vc, J2EEConstants.EJBJAR_DD_SHORT_NAME);
if(id == null) {
// Log, add "Cannot validate" to task list, and return.
logMissingRule(vc, id);
}
else {
IValidationRule ejbJarRule = EJBValidationRuleFactory.getFactory().getRule(vc, id);
if(ejbJarRule == null) {
logMissingRule(vc, id);
} else {
setValidated(ejbJarRule.getId(), null, ejbJar);
}
}
}
if(validatedClasses.size() > 0) {
// Check the children of the changed classes.
// This check must be done before the dependents, because
// the dependents of the children classes must be checked
// as well.
// Class never validated before, so check its children
for (int vC = 0; vC<validatedClasses.size(); vC++) {
List beans = (List)vc.loadModel(EJBValidatorModelEnum.EJB, new Object[]{validatedClasses.get(vC)});
if((beans == null) || (beans.size() == 0)) {
// The class is not a member of an enterprise bean.
continue;
}
Set rootValidatedClass = new HashSet();
rootValidatedClass.add(validatedClasses.get(vC));
JavaClass[] children = (JavaClass[])vc.loadModel(EJBValidatorModelEnum.CHILDREN, new Object[]{vc.getReporter(), rootValidatedClass});
if((children != null) && (children.length > 0)) {
Iterator bciterator = null;
Object id = null;
for(int c=0; c<children.length; c++) {
JavaClass child = children[c];
beans = (List)vc.loadModel(EJBValidatorModelEnum.EJB, new Object[]{child});
// The child is not a member of an enterprise bean.
if((beans == null) || (beans.size() == 0))
continue;
bciterator = beans.iterator();
while(bciterator.hasNext()) {
EnterpriseBean bean = (EnterpriseBean)bciterator.next();
id = EJBValidationRuleFactory.getFactory().getRuleId(vc, child, bean);
IValidationRule clazzRule = EJBValidationRuleFactory.getFactory().getRule(vc, id);
// This has already been logged by the AbstractEJBValidationRuleFactory, so just need to add "Cannot validate" to the task list.
if(clazzRule == null)
continue;
setValidated(clazzRule.getId(), bean, child);
}
}
}
}
validatedClasses.clear(); // Don't need this cache any more; free the memory.
}
// Now, validate the dependents.
targets.putAll(_validated);
Iterator iterator = targets.keySet().iterator();
while(iterator.hasNext()) {
Object id = iterator.next();
IValidationRule rule = EJBValidationRuleFactory.getFactory().getRule(vc, id);
if(rule == null) {
continue;
}
Set contexts = (Set)targets.get(id);
if(contexts == null) {
continue;
}
Iterator cIterator = contexts.iterator();
while(cIterator.hasNext()) {
TargetObject to = (TargetObject)cIterator.next();
Object targetParent = to.getTargetParent();
Object target = to.getTarget();
Set dependents = rule.getDependents();
if(dependents == null) {
continue;
}
Iterator dIterator = dependents.iterator();
while(dIterator.hasNext()) {
try {
IValidationRule dRule = (IValidationRule)dIterator.next();
Object dRuleTarget = dRule.getTarget(targetParent, target);
if(dRuleTarget != null) {
setValidated(dRule.getId(), targetParent, dRuleTarget);
}
}
catch(ValidationCancelledException e) {
throw e;
}
catch(Throwable exc) {
addInternalErrorMessage(getValidationContext(), exc);
}
finally {
EJBValidationRuleFactory.getFactory().release(rule);
}
}
}
}
}
finally {
// No matter what, clear the temporary caches.
targets.clear();
validatedClasses.clear();
// Now put the "validated" results in "done", because they weren't
// really validated; it was just a tracking mechanism.
targets.putAll(_validated);
_validated.clear(); // Clear the "validated" cache because the targets weren't really validated; they were just tracked.
}
}
@Override
protected String removeOldMessagesString() {
return EJBValidatorModelEnum.REMOVE_OLD_MESSAGES;
}
public void fullValidate(IEJBValidationContext vc) throws ValidationException {
removeOldMessages(vc,null); // null == no IFileDelta, null = don't track targets
EJBJar ejbJar = (EJBJar)vc.loadModel(EJBValidatorModelEnum.EJB_MODEL);
if(ejbJar == null) {
// Log, add "Cannot validate" to task list, and return.
// EJBProjectResources will already have logged the problem.
IMessage mssg = vc.getMessage();
mssg.setId(IEJBValidatorMessageConstants.CHKJ2905);
vc.addMessage(mssg);
return;
}
Object id = EJBValidationRuleFactory.getFactory().getRuleId(vc, J2EEConstants.EJBJAR_DD_SHORT_NAME);
if(id == null) {
// Log, add "Cannot validate" to task list, and return.
logMissingRule(vc, J2EEConstants.EJBJAR_DD_SHORT_NAME);
return;
}
IValidationRule ejbJarRule = EJBValidationRuleFactory.getFactory().getRule(vc, id);
if(ejbJarRule == null) {
logMissingRule(vc, id);
return;
}
run(ejbJarRule, null, ejbJar); // true= full validation
List beans = ejbJar.getEnterpriseBeans();
Iterator iterator = beans.iterator();
id = null;
while(iterator.hasNext()) {
EnterpriseBean bean = (EnterpriseBean)iterator.next();
JavaClass[] classes = getJavaClass(bean);
for(int i=0; i<classes.length; i++) {
JavaClass clazz = classes[i];
id = EJBValidationRuleFactory.getFactory().getRuleId(vc, clazz, bean);
IValidationRule clazzRule = EJBValidationRuleFactory.getFactory().getRule(vc, id);
if(clazzRule == null) {
// This has already been logged by the AbstractEJBValidationRuleFactory (if it's
// an error - this is expected if the key is a primitive primary key).
continue;
}
run(clazzRule, bean, clazz); // true = full validation
}
}
}
protected JavaClass[] getJavaClass(EnterpriseBean bean) {
int count = 0;
JavaClass[] classes = new JavaClass[6];
JavaClass ejbClass = bean.getEjbClass();
if((ejbClass != null) && (ejbClass.isExistingType())) {
classes[count++] = ejbClass;
}
JavaClass remoteClass = bean.getRemoteInterface();
if((remoteClass != null) && (remoteClass.isExistingType())) {
classes[count++] = remoteClass;
}
JavaClass localClass = bean.getLocalInterface();
if((localClass != null) && (localClass.isExistingType())) {
classes[count++] = localClass;
}
JavaClass homeClass = bean.getHomeInterface();
if((homeClass != null) && (homeClass.isExistingType())) {
classes[count++] = homeClass;
}
JavaClass localHomeClass = bean.getLocalHomeInterface();
if((localHomeClass != null) && (localHomeClass.isExistingType())) {
classes[count++] = localHomeClass;
}
if(bean instanceof Entity) {
JavaClass key = ((Entity)bean).getPrimaryKey();
if((key != null) && (key.isExistingType())) {
classes[count++] = key;
}
}
if(count == 6) {
return classes;
}
JavaClass[] result = new JavaClass[count];
System.arraycopy(classes, 0, result, 0, count);
return result;
}
public void incrementalValidate(IEJBValidationContext vc) throws ValidationException {
Map targets = new HashMap();
try {
removeOldMessages(vc,targets);
Iterator iterator = targets.keySet().iterator();
while(iterator.hasNext()) {
Object id = iterator.next();
IValidationRule rule = EJBValidationRuleFactory.getFactory().getRule(vc, id);
if(rule == null) {
continue;
}
Set contexts = (Set)targets.get(id);
if(contexts == null) {
continue;
}
Iterator cIterator = contexts.iterator();
while(cIterator.hasNext()) {
TargetObject to = (TargetObject)cIterator.next();
run(rule, to.getTargetParent(), to.getTarget());
}
}
}
finally {
targets.clear();
targets = null;
}
}
@Override
protected TargetObjectPool getTargetObjectPool() {
if(_targetObjectPoolSingleton == null) {
_targetObjectPoolSingleton = new TargetObjectPool(100);
}
return _targetObjectPoolSingleton;
}
/* (non-Javadoc)
* @see org.eclipse.jst.j2ee.internal.model.validation.AbstractEJBValidator#releaseRules(org.eclipse.jst.j2ee.internal.model.validation.ejb.IValidationRule)
*/
@Override
protected void releaseRules(IValidationRule rule) {
EJBValidationRuleFactory.getFactory().release(rule);
}
public ISchedulingRule getSchedulingRule(IValidationContext helper) {
return null;
}
@Override
public void cleanup(IReporter reporter){
// clear the map when the ejb validator is done see bug 187286
EJBValidationRuleFactory.getFactory().clearRuleMap(reporter);
}
@Override
public void validationFinishing(IProject project, ValidationState state, IProgressMonitor monitor) {
HashMap helperMap = ValidationRuleUtility.getHelperMap(project);
helperMap.clear();
ValidationRuleUtility.projectHelperMap.remove( helperMap );
helperMap = null;
super.validationFinishing(project, state, monitor);
}
}