blob: 474740f02981bd57ae24878242dac6d34616504f [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2007, 2008 SAP AG 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:
* Kaloyan Raev, kaloyan.raev@sap.com - initial API and implementation
*******************************************************************************/
package org.eclipse.jst.j2ee.internal.web.operations;
import static org.eclipse.jst.j2ee.application.internal.operations.IAnnotationsDataModel.USE_ANNOTATIONS;
import static org.eclipse.jst.j2ee.internal.common.operations.INewJavaClassDataModelProperties.CLASS_NAME;
import static org.eclipse.jst.j2ee.internal.common.operations.INewJavaClassDataModelProperties.CONSTRUCTOR;
import static org.eclipse.jst.j2ee.internal.common.operations.INewJavaClassDataModelProperties.MODIFIER_ABSTRACT;
import static org.eclipse.jst.j2ee.internal.common.operations.INewJavaClassDataModelProperties.MODIFIER_PUBLIC;
import static org.eclipse.jst.j2ee.internal.common.operations.INewJavaClassDataModelProperties.SOURCE_FOLDER;
import static org.eclipse.jst.j2ee.internal.common.operations.INewJavaClassDataModelProperties.SUPERCLASS;
import static org.eclipse.jst.j2ee.internal.web.operations.INewWebClassDataModelProperties.DESCRIPTION;
import static org.eclipse.jst.j2ee.internal.web.operations.INewWebClassDataModelProperties.DISPLAY_NAME;
import static org.eclipse.jst.j2ee.internal.web.operations.INewWebClassDataModelProperties.USE_EXISTING_CLASS;
import java.io.File;
import java.util.List;
import java.util.Set;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.jdt.core.Signature;
import org.eclipse.jem.util.emf.workbench.ProjectUtilities;
import org.eclipse.jst.j2ee.application.internal.operations.IAnnotationsDataModel;
import org.eclipse.jst.j2ee.internal.J2EEVersionConstants;
import org.eclipse.jst.j2ee.internal.common.J2EEVersionUtil;
import org.eclipse.jst.j2ee.internal.common.operations.NewJavaClassDataModelProvider;
import org.eclipse.jst.j2ee.internal.project.J2EEProjectUtilities;
import org.eclipse.wst.common.frameworks.datamodel.IDataModel;
import org.eclipse.wst.common.frameworks.datamodel.IDataModelProvider;
import org.eclipse.wst.common.frameworks.internal.plugin.WTPCommonPlugin;
/**
* The NewWebClassDataModelProvider is a subclass of
* NewJavaClassDataModelProvider and follows the IDataModel Operation and Wizard
* frameworks.
*
* @see org.eclipse.wst.common.frameworks.datamodel.IDataModelProvider
* @see org.eclipse.wst.common.frameworks.datamodel.IDataModelOperation
*
* This data model provider is a subclass of the NewJavaClassDataModelProvider,
* which stores base properties necessary in the creation of a default java
* class.
* @see org.eclipse.jst.j2ee.internal.common.operations.NewJavaClassDataModelProvider
*
* The NewWebClassDataModelProvider provides more specific properties for java
* class creation that are required in creating a web artifact java class. The
* data model provider is used to store these values for the
* AddWebClassOperation.
* @see org.eclipse.jst.j2ee.internal.web.operations.INewWebClassDataModelProperties
* That operation will create the web artifact java class based on the
* settings defined here in the data model.
* @see org.eclipse.jst.j2ee.internal.web.operations.AddWebClassOperation
*
* This data model properties implements the IAnnotationsDataModel to get the
* USE_ANNOTATIONS property for determining whether or not to generate an
* annotated java class.
* @see org.eclipse.jst.j2ee.application.internal.operations.IAnnotationsDataModel
*
* Clients can subclass this data model provider to cache and provide their own
* specific attributes. They should also provide their own validation methods,
* properties interface, and default values for the properties they add.
*
* The use of this class is EXPERIMENTAL and is subject to substantial changes.
*/
public abstract class NewWebClassDataModelProvider extends NewJavaClassDataModelProvider {
/**
* The fully qualified default superclass.
*/
private final static String DEFAULT_SUPERCLASS = ""; //$NON-NLS-1$
/**
* The cache of all the interfaces the web artifact java class will
* implement.
*/
protected List interfaceList;
private String classNameCache;
private String existingClassNameCache;
private static boolean useAnnotations = false;
/**
* Subclasses may extend this method to provide their own determination of
* whether or not certain properties should be disabled or enabled. This
* method does not accept null parameter. It will not return null. This
* implementation makes sure annotation support is only allowed on web
* projects of J2EE version 1.3 or higher.
*
* @see org.eclipse.wst.common.frameworks.datamodel.IDataModelProvider#isPropertyEnabled(String)
* @see IAnnotationsDataModel#USE_ANNOTATIONS
*
* @param propertyName
* @return boolean should property be enabled?
*/
@Override
public boolean isPropertyEnabled(String propertyName) {
// Annotations should only be enabled on a valid j2ee project of version 1.3 or higher
if (USE_ANNOTATIONS.equals(propertyName)) {
return !getBooleanProperty(USE_EXISTING_CLASS) && isAnnotationsSupported();
} else if (MODIFIER_PUBLIC.equals(propertyName)) {
return false;
} else if (MODIFIER_ABSTRACT.equals(propertyName)) {
return false;
} else if (CONSTRUCTOR.equals(propertyName)) {
return hasSuperClass();
}
// Otherwise return super implementation
return super.isPropertyEnabled(propertyName);
}
/**
* Subclasses may extend this method to add their own data model's
* properties as valid base properties.
*
* @see org.eclipse.wst.common.frameworks.datamodel.IDataModelProvider#getPropertyNames()
*/
@Override
public Set getPropertyNames() {
// Add web artifact specific properties defined in this data model
Set propertyNames = super.getPropertyNames();
propertyNames.add(DISPLAY_NAME);
propertyNames.add(DESCRIPTION);
propertyNames.add(USE_EXISTING_CLASS);
propertyNames.add(USE_ANNOTATIONS);
return propertyNames;
}
/**
* Subclasses may extend this method to provide their own default values for
* any of the properties in the data model hierarchy. This method does not
* accept a null parameter. It may return null. This implementation sets
* annotation use to be true.
*
* @see NewJavaClassDataModelProvider#getDefaultProperty(String)
* @see IDataModelProvider#getDefaultProperty(String)
*
* @param propertyName
* @return Object default value of property
*/
@Override
public Object getDefaultProperty(String propertyName) {
if (propertyName.equals(DISPLAY_NAME))
return Signature.getSimpleName(getStringProperty(CLASS_NAME));
else if (propertyName.equals(USE_ANNOTATIONS))
return shouldDefaultAnnotations();
else if (propertyName.equals(SUPERCLASS))
return DEFAULT_SUPERCLASS;
else if (propertyName.equals(USE_EXISTING_CLASS))
return Boolean.FALSE;
else if (propertyName.equals(CONSTRUCTOR))
return hasSuperClass();
// Otherwise check super for default value for property
return super.getDefaultProperty(propertyName);
}
/**
* Subclasses may extend this method to add their own specific behavior when
* a certain property in the data model hierarchy is set. this method does
* not accept null for the property name, but it will for propertyValue. It
* will not return null. It will return false if the set fails. This
* implementation verifies the display name is set to the class name, that
* the annotations is disabled/enabled properly, and that the target project
* name is determined from the source folder setting.
*
* @see org.eclipse.wst.common.frameworks.datamodel.IDataModelProvider#propertySet(String,
* Object)
*
* @param propertyName
* @param propertyValue
* @return boolean was property set?
*/
@Override
public boolean propertySet(String propertyName, Object propertyValue) {
// If annotations is changed, notify an enablement change
if (propertyName.equals(USE_ANNOTATIONS)) {
useAnnotations = ((Boolean) propertyValue).booleanValue();
if (useAnnotations && !isAnnotationsSupported())
return true;
model.notifyPropertyChange(USE_ANNOTATIONS, IDataModel.ENABLE_CHG);
}
// If the source folder is changed, ensure we have the correct project name
if (propertyName.equals(SOURCE_FOLDER)) {
// Get the project name from the source folder name
String sourceFolder = (String) propertyValue;
int index = sourceFolder.indexOf(File.separator);
String projectName = sourceFolder;
if (index == 0)
projectName = sourceFolder.substring(1);
index = projectName.indexOf(File.separator);
if (index != -1) {
projectName = projectName.substring(0, index);
setProperty(PROJECT_NAME, projectName);
}
}
// Call super to set the property on the data model
boolean result = super.propertySet(propertyName, propertyValue);
// If class name is changed, update the display name to be the same
if (propertyName.equals(CLASS_NAME) && !model.isPropertySet(DISPLAY_NAME)) {
model.notifyPropertyChange(DISPLAY_NAME, IDataModel.DEFAULT_CHG);
}
// After the property is set, if project changed, update the nature and the annotations
// enablement
if (propertyName.equals(COMPONENT_NAME)) {
model.notifyPropertyChange(USE_ANNOTATIONS, IDataModel.ENABLE_CHG);
}
// After property is set, if annotations is set to true, update its value based on the new
// level of the project
if (getBooleanProperty(USE_ANNOTATIONS)) {
if (!isAnnotationsSupported())
setBooleanProperty(USE_ANNOTATIONS, false);
}
if (propertyName.equals(USE_EXISTING_CLASS)) {
model.notifyPropertyChange(USE_ANNOTATIONS, IDataModel.ENABLE_CHG);
if (((Boolean) propertyValue).booleanValue()) {
classNameCache = getStringProperty(CLASS_NAME);
setProperty(CLASS_NAME, existingClassNameCache);
} else {
existingClassNameCache = getStringProperty(CLASS_NAME);
setProperty(CLASS_NAME, classNameCache);
}
}
// if super class is changed, notify the constructor checkbox to update
// its enabled state
if (SUPERCLASS.equals(propertyName)) {
model.notifyPropertyChange(CONSTRUCTOR, IDataModel.ENABLE_CHG);
if (!hasSuperClass()) {
model.setProperty(CONSTRUCTOR, null);
}
model.notifyPropertyChange(CONSTRUCTOR, IDataModel.DEFAULT_CHG);
}
// Return whether property was set
return result;
}
/**
* This method is used to determine if annotations should try to enable
* based on workspace settings
*
* @return does any valid annotation provider or xdoclet handler exist
*/
//TODO add this method back in for defect 146696
// protected boolean isAnnotationProviderDefined() {
// boolean isControllerEnabled = AnnotationsControllerManager.INSTANCE.isAnyAnnotationsSupported();
// final String preferred = AnnotationPreferenceStore.getProperty(AnnotationPreferenceStore.ANNOTATIONPROVIDER);
// IAnnotationProvider annotationProvider = null;
// boolean isProviderEnabled = false;
// if (preferred != null) {
// try {
// annotationProvider = AnnotationUtilities.findAnnotationProviderByName(preferred);
// } catch (Exception ex) {
// //Default
// }
// if (annotationProvider != null && annotationProvider.isValid())
// isProviderEnabled = true;
// }
// return isControllerEnabled || isProviderEnabled;
// }
/**
* This method checks to see if valid annotation providers exist and if
* valid project version levels exist.
*
* @return should annotations be supported for this project in this
* workspace
*/
protected boolean isAnnotationsSupported() {
//TODO add this check back in for defect 146696
// if (!isAnnotationProviderDefined())
// return false;
if (!model.isPropertySet(PROJECT_NAME))
return true;
if (getStringProperty(PROJECT_NAME).equals("")) //$NON-NLS-1$
return true;
IProject project = ProjectUtilities.getProject(getStringProperty(PROJECT_NAME));
String moduleName = getStringProperty(COMPONENT_NAME);
if (project == null || moduleName == null || moduleName.equals(""))return true; //$NON-NLS-1$
int j2eeVersion = J2EEVersionUtil.convertVersionStringToInt(J2EEProjectUtilities.getJ2EEProjectVersion(project));
return j2eeVersion > J2EEVersionConstants.VERSION_1_2;
}
/**
* Subclasses may extend this method to provide their own validation on any
* of the valid data model properties in the hierarchy. It does not accept a
* null parameter. This method will not return null.
*
* @see NewJavaClassDataModelProvider#validate(String)
*
* @param propertyName
* @return IStatus is property value valid?
*/
@Override
public IStatus validate(String propertyName) {
if (propertyName.equals(SUPERCLASS)) {
// If our default is the superclass, we know it is ok
if (getStringProperty(propertyName).equals(DEFAULT_SUPERCLASS))
return WTPCommonPlugin.OK_STATUS;
}
if (propertyName.equals(CLASS_NAME)) {
if (getStringProperty(propertyName).length() !=0 && getBooleanProperty(USE_EXISTING_CLASS)) {
return WTPCommonPlugin.OK_STATUS;
}
}
// Otherwise defer to super to validate the property
return super.validate(propertyName);
}
/**
* This method is intended for internal use only. It provides a simple
* algorithm for detecting if there are duplicate entries in a list. It will
* accept a null parameter. It will not return null.
*
* @see NewWebClassDataModelProvider#validateInitParamList(List)
* @see NewWebClassDataModelProvider#validateURLMappingList(List)
*
* @param input
* @return boolean are there dups in the list?
*/
protected boolean hasDuplicatesInStringArrayList(List input) {
// If list is null or empty return false
if (input == null)
return false;
int n = input.size();
boolean dup = false;
// nested for loops to check each element to see if other elements are the same
for (int i = 0; i < n; i++) {
String[] sArray1 = (String[]) input.get(i);
for (int j = i + 1; j < n; j++) {
String[] sArray2 = (String[]) input.get(j);
if (isTwoStringArraysEqual(sArray1, sArray2)) {
dup = true;
break;
}
}
if (dup)
break;
}
// Return boolean status for duplicates
return dup;
}
/**
* This method is intended for internal use only. This checks to see if the
* two string arrays are equal. If either of the arrays are null or empty,
* it returns false.
*
* @see NewWebClassDataModelProvider#hasDuplicatesInStringArrayList(List)
*
* @param sArray1
* @param sArray2
* @return boolean are Arrays equal?
*/
protected boolean isTwoStringArraysEqual(String[] sArray1, String[] sArray2) {
// If either array is null, return false
if (sArray1 == null || sArray2 == null)
return false;
int n1 = sArray1.length;
int n2 = sArray1.length;
// If either array is empty, return false
if (n1 == 0 || n2 == 0)
return false;
// If they don't have the same length, return false
if (n1 != n2)
return false;
// If their first elements do not match, return false
if (!sArray1[0].equals(sArray2[0]))
return false;
// Otherwise return true
return true;
}
protected boolean hasSuperClass() {
String superClass = model.getStringProperty(SUPERCLASS);
return (superClass == null) ? false : superClass.trim().length() > 0;
}
/**
* @return boolean should the default annotations be true?
*/
private static Boolean shouldDefaultAnnotations() {
if (useAnnotations)
return Boolean.TRUE;
return Boolean.FALSE;
}
}