/*******************************************************************************
* Copyright (c) 2007 Red Hat, Inc.
* Distributed under license by Red Hat, Inc. All rights reserved.
* This program is 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:
* Red Hat, Inc. - initial API and implementation
******************************************************************************/
package org.jboss.tools.seam.internal.core.validation;
import java.util.HashSet;
import java.util.Set;
import org.eclipse.core.resources.IContainer;
import org.eclipse.core.resources.IMarker;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Path;
import org.eclipse.core.runtime.jobs.ISchedulingRule;
import org.eclipse.core.runtime.preferences.IEclipsePreferences;
import org.eclipse.datatools.connectivity.IConnectionProfile;
import org.eclipse.datatools.connectivity.ProfileManager;
import org.eclipse.jdt.core.JavaConventions;
import org.eclipse.jdt.internal.compiler.impl.CompilerOptions;
import org.eclipse.wst.validation.internal.core.ValidationException;
import org.eclipse.wst.validation.internal.operations.WorkbenchContext;
import org.eclipse.wst.validation.internal.operations.WorkbenchReporter;
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;
import org.eclipse.wst.validation.internal.provisional.core.IValidator;
import org.eclipse.wst.validation.internal.provisional.core.IValidatorJob;
import org.jboss.tools.common.validation.ContextValidationHelper;
import org.jboss.tools.common.validation.IProjectValidationContext;
import org.jboss.tools.common.validation.IValidationErrorManager;
import org.jboss.tools.common.validation.ProblemMessage;
import org.jboss.tools.common.validation.ValidationErrorManager;
import org.jboss.tools.seam.core.ISeamProject;
import org.jboss.tools.seam.core.SeamCorePlugin;
import org.jboss.tools.seam.core.SeamPreferences;
import org.jboss.tools.seam.core.project.facet.SeamRuntimeManager;
import org.jboss.tools.seam.internal.core.project.facet.ISeamFacetDataModelProperties;
import org.jboss.tools.seam.internal.core.refactoring.SeamProjectChange;
/**
* Validates seam project properties.
* @author Alexey Kazakov
*/
public class SeamProjectPropertyValidator implements IValidatorJob {
public static final String MESSAGE_ID_ATTRIBUTE_NAME = "Seam_property_message_id"; //$NON-NLS-1$
public static final int INVALID_SEAM_RUNTIME_ID = 1;
private IValidationErrorManager errorManager;
private Set<String> validatedProjects = new HashSet<String>();
private static Set<String> beingValidatedProjects = new HashSet<String>();
private IReporter reporter;
/* (non-Javadoc)
* @see org.eclipse.wst.validation.internal.provisional.core.IValidatorJob#getSchedulingRule(org.eclipse.wst.validation.internal.provisional.core.IValidationContext)
*/
public ISchedulingRule getSchedulingRule(IValidationContext helper) {
return null;
}
protected IValidationErrorManager getTestValidationErrorManager(){
return null;
}
/* (non-Javadoc)
* @see org.eclipse.wst.validation.internal.provisional.core.IValidatorJob#validateInJob(org.eclipse.wst.validation.internal.provisional.core.IValidationContext, org.eclipse.wst.validation.internal.provisional.core.IReporter)
*/
public IStatus validateInJob(IValidationContext helper, IReporter reporter) throws ValidationException {
validatedProjects.clear();
try {
this.reporter = reporter;
IProject project = ((WorkbenchContext)helper).getProject();
if(!project.isAccessible()) {
return OK_STATUS;
}
ISeamProject seamProject = SeamCorePlugin.getSeamProject(project, false);
errorManager = getTestValidationErrorManager();
if(errorManager == null)
errorManager = new SeamValidationErrorManager() {
/* (non-Javadoc)
* @see org.jboss.tools.jst.web.kb.internal.validation.ValidationErrorManager#getMarkerOwner()
*/
@Override
protected Class getMarkerOwner() {
return SeamProjectPropertyValidator.this.getClass();
}
/*
* (non-Javadoc)
* @see org.jboss.tools.jst.web.kb.internal.validation.ValidationErrorManager#init(org.eclipse.core.resources.IProject, org.jboss.tools.jst.web.kb.internal.validation.ContextValidationHelper, org.jboss.tools.jst.web.kb.validation.IProjectValidationContext, org.eclipse.wst.validation.internal.provisional.core.IValidator, org.eclipse.wst.validation.internal.provisional.core.IReporter)
*/
@Override
public void init(IProject project,
ContextValidationHelper validationHelper,
IProjectValidationContext context,
IValidator manager, IReporter reporter) {
setProject(project);
setValidationManager(manager);
setReporter(reporter);
setMarkerId(SeamValidationErrorManager.MARKED_SEAM_PROJECT_MESSAGE_GROUP);
setValidationContext(context);
}
@Override
protected void registerPreferenceInfo() {
// TODO Auto-generated method stub
}
};
errorManager.init(project, null, null, this, reporter);
if(seamProject!=null) {
validateSeamProject(seamProject);
}
IProject[] ps = ResourcesPlugin.getWorkspace().getRoot().getProjects();
String projectName = project.getName();
for (int i = 0; i < ps.length; i++) {
if(ps[i]!=project) {
validateProject(projectName, ps[i]);
}
}
} finally {
finishValidating();
}
return OK_STATUS;
}
synchronized private void finishValidating() {
beingValidatedProjects.removeAll(validatedProjects);
}
synchronized private boolean canStartValidating(IProject project) {
String name = project.getName();
if(validatedProjects.contains(name) || beingValidatedProjects.contains(name)) {
return false;
}
validatedProjects.add(name);
beingValidatedProjects.add(name);
return true;
}
private void validateProject(String nameOfChangedProject, IProject checkingProject) {
ISeamProject seamProject = SeamCorePlugin.getSeamProject(checkingProject, false);
if(seamProject==null) {
return;
}
IEclipsePreferences pref = SeamCorePlugin.getSeamPreferences(checkingProject);
for (int i = 0; i < SeamProjectChange.PROJECT_NAME_PROPERTIES.length; i++) {
if(nameOfChangedProject.equals(pref.get(SeamProjectChange.PROJECT_NAME_PROPERTIES[i], null))) {
validateSeamProject(seamProject);
return;
}
}
for (int i = 0; i < SeamProjectChange.FOLDER_PROPERTIES.length; i++) {
if(pref.get(SeamProjectChange.FOLDER_PROPERTIES[i], "").startsWith("/" + nameOfChangedProject + "/")) {
validateSeamProject(seamProject);
return;
}
}
}
/**
* Returns true if the project with this name exists.
* @param projectName
* @param canBeEmpty if "true" and the project name is empty (null or "") then it is valid.
* @return
*/
public static boolean isProjectNameValid(String projectName, boolean canBeEmpty) {
if(projectName==null || projectName.length()==0) {
return canBeEmpty;
}
if(new Path("/").isValidSegment(projectName)) {
IProject project = ResourcesPlugin.getWorkspace().getRoot().getProject(projectName);
if(project.exists()) {
return true;
}
}
return false;
}
/**
* Returns true if the folder with this name exists.
* @param folderPath
* @param canBeEmpty if "true" and the folder path is empty (null or "") then it is valid.
* @return
*/
public static boolean isFolderPathValid(String folderPath, boolean canBeEmpty) {
if(folderPath==null || folderPath.length()==0) {
return canBeEmpty;
}
if(new Path("/").isValidPath(folderPath)) {
IResource folder = ResourcesPlugin.getWorkspace().getRoot().findMember(folderPath);
if(folder!=null && (folder instanceof IContainer) && folder.exists()) {
return true;
}
}
return false;
}
/**
* Returns true if the package name is valid (it does not have to exist).
* @param packageName
* @param canBeEmpty if "true" and the package name is empty (null or "") then it is valid.
* @return
*/
public static boolean isPackageNameValid(String packageName, boolean canBeEmpty) {
if(packageName==null || packageName.length()==0) {
return canBeEmpty;
}
IStatus status = JavaConventions.validatePackageName(packageName, CompilerOptions.VERSION_1_5, CompilerOptions.VERSION_1_5);
if(status.getSeverity()==IStatus.ERROR) {
return false;
}
return true;
}
/**
* Returns true if the profiler exists.
* @param profilerName
* @param canBeEmpty if "true" and the profiler name is empty (null or "") then it is valid.
* @return
*/
public static boolean isConnectionProfileValid(String profilerName, boolean canBeEmpty) {
if(profilerName==null || profilerName.length()==0) {
return canBeEmpty;
}
IConnectionProfile[] profiles = ProfileManager.getInstance().getProfilesByCategory("org.eclipse.datatools.connectivity.db.category"); //$NON-NLS-1$
for (IConnectionProfile connectionProfile : profiles) {
if(profilerName.equals(connectionProfile.getName())) {
return true;
}
}
return false;
}
private void validateProjectName(IProject targetProject, String projectName, boolean canBeEmpty, String messageId) {
if(!isProjectNameValid(projectName, canBeEmpty)) {
// Mark invalid project name
addError(messageId, SeamPreferences.INVALID_PROJECT_SETTINGS, new String[]{projectName!=null?projectName:"", targetProject.getName()}, targetProject);
}
}
private void validateSorceFolder(IProject targetProject, String folderPath, String packageName, String srcFolderMessageID, String packageMessageId) {
if(!isFolderPathValid(folderPath, true)) {
// Mark invalid source folder path
addError(srcFolderMessageID, SeamPreferences.INVALID_PROJECT_SETTINGS, new String[]{folderPath!=null?folderPath:"", targetProject.getName()}, targetProject);
}
if(!isPackageNameValid(packageName, true)) {
// Mark invalid source folder path
addError(packageMessageId, SeamPreferences.INVALID_PROJECT_SETTINGS, new String[]{packageName!=null?packageName:"", targetProject.getName()}, targetProject);
}
}
private void validateSeamProject(ISeamProject seamProject) {
IProject project = seamProject.getProject();
if(!project.isAccessible()) {
return;
}
if(!canStartValidating(project)) {
return;
}
WorkbenchReporter.removeAllMessages(project, new String[]{this.getClass().getName()}, null);
if(!SeamPreferences.shouldValidateSettings(project)) {
return;
}
IMessage problemMessage = new ProblemMessage(SeamValidationMessages.VALIDATING_PROJECT, IMessage.NORMAL_SEVERITY, new String[]{project.getName()});
reporter.displaySubtask(this, problemMessage);
IEclipsePreferences pref = SeamCorePlugin.getSeamPreferences(project);
String parentProject = pref.get(ISeamFacetDataModelProperties.SEAM_PARENT_PROJECT, null);
if(parentProject!=null) {
// EJB or Test project
validateProjectName(project, parentProject, false, SeamValidationMessages.INVALID_PARENT_PROJECT);
} else {
// War project
String settingVersion = pref.get(ISeamFacetDataModelProperties.SEAM_SETTINGS_VERSION, ISeamFacetDataModelProperties.SEAM_SETTINGS_VERSION_1_0);
String seamRuntimeName = pref.get(ISeamFacetDataModelProperties.SEAM_RUNTIME_NAME, null);
if(seamRuntimeName!=null && seamRuntimeName.length()>0 && (SeamRuntimeManager.getInstance().findRuntimeByName(seamRuntimeName) == null)) {
// Mark unknown runtime
addError(SeamValidationMessages.INVALID_SEAM_RUNTIME, SeamPreferences.INVALID_PROJECT_SETTINGS, new String[]{seamRuntimeName!=null?seamRuntimeName:"", project.getName()}, project, INVALID_SEAM_RUNTIME_ID);
}
if(ISeamFacetDataModelProperties.DEPLOY_AS_EAR.equals(pref.get(ISeamFacetDataModelProperties.JBOSS_AS_DEPLOY_AS, null))) {
validateProjectName(project, pref.get(ISeamFacetDataModelProperties.SEAM_EJB_PROJECT, null), true, SeamValidationMessages.INVALID_EJB_PROJECT);
}
String viewFolder = pref.get(ISeamFacetDataModelProperties.WEB_CONTENTS_FOLDER, null);
if(!isFolderPathValid(viewFolder, true)) {
// Mark unknown View folder
addError(SeamValidationMessages.INVALID_WEBFOLDER, SeamPreferences.INVALID_PROJECT_SETTINGS, new String[]{viewFolder!=null?viewFolder:"", project.getName()}, project);
}
validateSorceFolder(project, pref.get(ISeamFacetDataModelProperties.ENTITY_BEAN_SOURCE_FOLDER, null),
pref.get(ISeamFacetDataModelProperties.ENTITY_BEAN_PACKAGE_NAME, null),
SeamValidationMessages.INVALID_MODEL_SRC,
SeamValidationMessages.INVALID_MODEL_PACKAGE_NAME);
validateSorceFolder(project, pref.get(ISeamFacetDataModelProperties.SESSION_BEAN_SOURCE_FOLDER, null),
pref.get(ISeamFacetDataModelProperties.SESSION_BEAN_PACKAGE_NAME, null),
SeamValidationMessages.INVALID_ACTION_SRC,
SeamValidationMessages.INVALID_ACTION_PACKAGE_NAME);
String createTestString = pref.get(ISeamFacetDataModelProperties.TEST_CREATING, null);
if(settingVersion.equals(ISeamFacetDataModelProperties.SEAM_SETTINGS_VERSION_1_0) ||
"true".equals(createTestString)) {
validateProjectName(project, pref.get(ISeamFacetDataModelProperties.SEAM_TEST_PROJECT, null), true, SeamValidationMessages.INVALID_TEST_PROJECT);
validateSorceFolder(project, pref.get(ISeamFacetDataModelProperties.TEST_SOURCE_FOLDER, null),
pref.get(ISeamFacetDataModelProperties.TEST_CASES_PACKAGE_NAME, null),
SeamValidationMessages.INVALID_TEST_SRC,
SeamValidationMessages.INVALID_TEST_PACKAGE_NAME);
}
// String connectionProfile = pref.get(ISeamFacetDataModelProperties.SEAM_CONNECTION_PROFILE, null);
// if(!isConnectionProfileValid(connectionProfile, true)) {
// addError(INVALID_CONNECTION_NAME, SeamPreferences.INVALID_PROJECT_SETTINGS, new String[]{connectionProfile!=null?connectionProfile:"", project.getName()}, project);
// }
}
return;
}
/* (non-Javadoc)
* @see org.eclipse.wst.validation.internal.provisional.core.IValidator#cleanup(org.eclipse.wst.validation.internal.provisional.core.IReporter)
*/
public void cleanup(IReporter reporter) {
// finishValidating();
}
/* (non-Javadoc)
* @see org.eclipse.wst.validation.internal.provisional.core.IValidator#validate(org.eclipse.wst.validation.internal.provisional.core.IValidationContext, org.eclipse.wst.validation.internal.provisional.core.IReporter)
*/
public void validate(IValidationContext helper, IReporter reporter) throws ValidationException {
validateInJob(helper, reporter);
}
public IMarker addError(String message, String preferenceKey,
String[] messageArguments, IResource target, int messageId) {
IMarker marker = errorManager.addError(message, preferenceKey, messageArguments, target);
try {
if(marker!=null) {
marker.setAttribute(MESSAGE_ID_ATTRIBUTE_NAME, new Integer(messageId));
}
} catch(CoreException ex) {
SeamCorePlugin.getDefault().logError(ex);
}
return marker;
}
public IMarker addError(String message, String preferenceKey,
String[] messageArguments, IResource target) {
return errorManager.addError(message, preferenceKey, messageArguments, target);
}
}