/******************************************************************************* * 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); } }