/******************************************************************************* * Copyright (c) 2007, 2012 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.internal.web.plugin.WebPlugin; 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. * */ 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 { // check to see if it is Java EE 6 or 7 return (FacetedProjectFramework.hasProjectFacet(project, WebFacetUtils.WEB_FACET.getId(), WebFacetUtils.WEB_30.getVersionString()) || FacetedProjectFramework.hasProjectFacet(project, WebFacetUtils.WEB_FACET.getId(), WebFacetUtils.WEB_31.getVersionString()) || FacetedProjectFramework.hasProjectFacet(project, WebFacetUtils.WEBFRAGMENT_FACET.getId(), WebFacetUtils.WEBFRAGMENT_30.getVersionString()) || FacetedProjectFramework.hasProjectFacet(project, WebFacetUtils.WEBFRAGMENT_FACET.getId(), WebFacetUtils.WEBFRAGMENT_31.getVersionString())); } catch (CoreException e) { WebPlugin.log(e); } } 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; } }