| /******************************************************************************* |
| * 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.JAVA_EE_VERSION; |
| import static org.eclipse.jst.j2ee.internal.web.operations.INewWebClassDataModelProperties.REGISTER_IN_WEB_XML; |
| 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.resources.ResourcesPlugin; |
| import org.eclipse.core.runtime.CoreException; |
| 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.jst.j2ee.project.JavaEEProjectUtilities; |
| import org.eclipse.jst.j2ee.web.project.facet.WebFacetUtils; |
| import org.eclipse.wst.common.componentcore.internal.util.FacetedProjectUtilities; |
| 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; |
| import org.eclipse.wst.common.project.facet.core.FacetedProjectFramework; |
| |
| /** |
| * 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 = ""; //$NON-NLS-1$ |
| private String existingClassNameCache = ""; //$NON-NLS-1$ |
| |
| 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(REGISTER_IN_WEB_XML); |
| propertyNames.add(DISPLAY_NAME); |
| propertyNames.add(DESCRIPTION); |
| propertyNames.add(USE_EXISTING_CLASS); |
| propertyNames.add(USE_ANNOTATIONS); |
| propertyNames.add(JAVA_EE_VERSION); |
| |
| 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(); |
| else if (propertyName.equals(REGISTER_IN_WEB_XML)){ |
| return !isJavaEE6Project(); |
| } else if (JAVA_EE_VERSION.equals(propertyName)){ |
| return getJavaEEVersion(); |
| } |
| // Otherwise check super for default value for property |
| return super.getDefaultProperty(propertyName); |
| } |
| |
| @SuppressWarnings("restriction") |
| public boolean isJavaEE6Project() { |
| IProject project = ResourcesPlugin.getWorkspace().getRoot().getProject(getStringProperty(PROJECT_NAME)); |
| if (project != null && project.isAccessible()){ |
| try { |
| return (FacetedProjectFramework.hasProjectFacet(project, WebFacetUtils.WEB_FACET.getId(), WebFacetUtils.WEB_30.getVersionString()) |
| || FacetedProjectFramework.hasProjectFacet(project, WebFacetUtils.WEBFRAGMENT_FACET.getId(), WebFacetUtils.WEBFRAGMENT_30.getVersionString())); |
| } catch (CoreException e) { |
| e.printStackTrace(); |
| } |
| } |
| return false; |
| } |
| |
| @SuppressWarnings("restriction") |
| public String getJavaEEVersion() { |
| IProject project = ResourcesPlugin.getWorkspace().getRoot().getProject(getStringProperty(PROJECT_NAME)); |
| String id = null; |
| if(JavaEEProjectUtilities.isDynamicWebProject(project)){ |
| id = WebFacetUtils.WEB_FACET.getId(); |
| }else { |
| id = WebFacetUtils.WEBFRAGMENT_FACET.getId(); |
| } |
| return FacetedProjectUtilities.getProjectFacetVersion(project, id).getVersionString(); |
| } |
| |
| /** |
| * 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; |
| } |
| |
| } |