| /******************************************************************************* |
| * Copyright (c) 2003, 2005 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.internal.web.operations; |
| |
| import java.lang.reflect.InvocationTargetException; |
| import java.net.URL; |
| import java.util.Iterator; |
| import java.util.Set; |
| |
| import org.eclipse.core.commands.ExecutionException; |
| import org.eclipse.core.resources.IFile; |
| import org.eclipse.core.resources.IFolder; |
| import org.eclipse.core.resources.IMarker; |
| import org.eclipse.core.resources.IProject; |
| import org.eclipse.core.resources.IResource; |
| import org.eclipse.core.resources.IWorkspaceRoot; |
| import org.eclipse.core.resources.ResourcesPlugin; |
| import org.eclipse.core.runtime.CoreException; |
| import org.eclipse.core.runtime.IAdaptable; |
| import org.eclipse.core.runtime.IProgressMonitor; |
| import org.eclipse.core.runtime.IStatus; |
| import org.eclipse.core.runtime.NullProgressMonitor; |
| import org.eclipse.core.runtime.Path; |
| import org.eclipse.emf.codegen.jet.JETEmitter; |
| import org.eclipse.emf.codegen.jet.JETException; |
| import org.eclipse.jdt.core.ICompilationUnit; |
| import org.eclipse.jdt.core.IJavaModelMarker; |
| import org.eclipse.jdt.core.IPackageFragment; |
| import org.eclipse.jdt.core.IPackageFragmentRoot; |
| import org.eclipse.jdt.core.JavaModelException; |
| import org.eclipse.jem.util.emf.workbench.ProjectUtilities; |
| import org.eclipse.jem.util.logger.proxy.Logger; |
| import org.eclipse.jst.common.internal.annotations.controller.AnnotationsController; |
| import org.eclipse.jst.common.internal.annotations.controller.AnnotationsControllerManager; |
| import org.eclipse.jst.common.internal.annotations.controller.AnnotationsControllerManager.Descriptor; |
| import org.eclipse.jst.j2ee.application.internal.operations.IAnnotationsDataModel; |
| import org.eclipse.jst.j2ee.internal.common.operations.INewJavaClassDataModelProperties; |
| import org.eclipse.jst.j2ee.internal.project.WTPJETEmitter; |
| import org.eclipse.jst.j2ee.internal.web.plugin.WebPlugin; |
| import org.eclipse.wst.common.componentcore.datamodel.FacetInstallDataModelProvider; |
| import org.eclipse.wst.common.componentcore.datamodel.FacetProjectCreationDataModelProvider; |
| import org.eclipse.wst.common.componentcore.datamodel.properties.IFacetDataModelProperties; |
| import org.eclipse.wst.common.componentcore.datamodel.properties.IFacetProjectCreationDataModelProperties; |
| import org.eclipse.wst.common.componentcore.datamodel.properties.IFacetProjectCreationDataModelProperties.FacetDataModelMap; |
| import org.eclipse.wst.common.componentcore.internal.operation.ArtifactEditProviderOperation; |
| import org.eclipse.wst.common.frameworks.datamodel.DataModelFactory; |
| import org.eclipse.wst.common.frameworks.datamodel.IDataModel; |
| import org.eclipse.wst.common.frameworks.internal.enablement.nonui.WFTWrappedException; |
| import org.eclipse.wst.common.frameworks.internal.plugin.WTPCommonPlugin; |
| import org.eclipse.wst.common.project.facet.core.IFacetedProject; |
| import org.eclipse.wst.common.project.facet.core.IProjectFacetVersion; |
| import org.eclipse.wst.common.project.facet.core.ProjectFacetsManager; |
| |
| /** |
| * The NewServletClassOperation is an IDataModelOperation following the |
| * IDataModel wizard and operation framework. |
| * |
| * @see org.eclipse.wst.common.frameworks.datamodel.IDataModelOperation |
| * @see org.eclipse.wst.common.frameworks.datamodel.IDataModelProvider |
| * |
| * It extends ArtifactEditProviderOperation to provide servlet specific java |
| * class generation. |
| * @see org.eclipse.wst.common.componentcore.internal.operation.ArtifactEditProviderOperation |
| * |
| * This operation is used by the AddServletOperation to generate either an |
| * annotated or non annotated java class for an added servlet. It shares the |
| * NewServletClassDataModelProvider with the AddServletOperation to store the |
| * appropriate properties required to generate the new servlet. |
| * @see org.eclipse.jst.j2ee.internal.web.operations.AddServletOperation |
| * @see org.eclipse.jst.j2ee.internal.web.operations.NewServletClassDataModelProvider |
| * |
| * In the annotated case, a WTPJetEmitter servlet template is created and used |
| * to generate the servlet java class with the embedded annotated tags. |
| * @see org.eclipse.jst.j2ee.internal.project.WTPJETEmitter |
| * @see org.eclipse.jst.j2ee.internal.web.operations.CreateServletTemplateModel |
| * |
| * In the non annotated case, the same emitter is used to create the class with |
| * the non annotated servlet template so the annotated tags are omitted. |
| * |
| * Subclasses may extend this operation to provide their own specific servlet |
| * java class generation. The execute method may be extended to do so. Also, |
| * generateUsingTemplates is exposed. |
| * |
| * The use of this class is EXPERIMENTAL and is subject to substantial changes. |
| */ |
| public class NewServletClassOperation extends ArtifactEditProviderOperation { |
| |
| /** |
| * XDoclet facet constants |
| */ |
| private static final String JST_WEB_XDOCLET_VERSION = "1.2.3"; |
| private static final String JST_WEB_XDOCLET = "jst.web.xdoclet"; |
| |
| private static final String WEB_PLUGIN_JAR = "org.eclipse.jst.j2ee.web_1.0.0.jar"; //$NON-NLS-1$ |
| |
| /** |
| * The extension name for a java class |
| */ |
| private static final String DOT_JAVA = ".java"; //$NON-NLS-1$ |
| |
| /** |
| * platform plugin beginning for URI string |
| */ |
| // private static final String PLATFORM_PLUGIN = "platform:/plugin/"; |
| // //$NON-NLS-1$ |
| /** |
| * variable for the web plugin |
| */ |
| protected static final String WEB_PLUGIN = "WEB_PLUGIN"; //$NON-NLS-1$ |
| |
| /** |
| * folder location of the servlet creation templates diretory |
| */ |
| protected static final String TEMPLATE_DIR = "/templates/"; //$NON-NLS-1$ |
| |
| /** |
| * name of the template emitter to be used to generate the deployment |
| * descriptor from the tags |
| */ |
| protected static final String TEMPLATE_EMITTER = "org.eclipse.jst.j2ee.ejb.annotations.emitter.template"; //$NON-NLS-1$ |
| |
| /** |
| * id of the builder used to kick off generation of web metadata based on |
| * parsing of annotations |
| */ |
| protected static final String BUILDER_ID = "builderId"; //$NON-NLS-1$ |
| |
| /** |
| * This is the constructor which should be used when creating a |
| * NewServletClassOperation. An instance of the NewServletClassDataModel |
| * should be passed in. This does not accept null parameter. It will not |
| * return null. |
| * |
| * @see ArtifactEditProviderOperation#ArtifactEditProviderOperation(IDataModel) |
| * @see NewServletClassDataModel |
| * |
| * @param dataModel |
| * @return NewServletClassOperation |
| */ |
| public NewServletClassOperation(IDataModel dataModel) { |
| super(dataModel); |
| } |
| |
| /** |
| * Subclasses may extend this method to add their own actions during |
| * execution. The implementation of the execute method drives the running of |
| * the operation. This implemenatation will create the java source folder, |
| * create the java package, and then if using annotations, will use |
| * templates to generate an annotated servlet java class, or if it is not |
| * annotated, the servlet java class file will be created without the |
| * annotated tags using templates. Optionally, subclasses may extend the |
| * generateUsingTemplates or createJavaFile method rather than extend the |
| * execute method. This method will accept a null paramter. |
| * |
| * @see org.eclipse.wst.common.frameworks.internal.operation.WTPOperation#execute(org.eclipse.core.runtime.IProgressMonitor) |
| * @see NewServletClassOperation#generateUsingTemplates(IProgressMonitor, |
| * IPackageFragment) |
| * |
| * @param monitor |
| * @throws CoreException |
| * @throws InterruptedException |
| * @throws InvocationTargetException |
| */ |
| public IStatus doExecute(IProgressMonitor monitor, IAdaptable info) throws ExecutionException { |
| // Create source folder if it does not exist |
| createJavaSourceFolder(); |
| // Create java package if it does not exist |
| IPackageFragment pack = createJavaPackage(); |
| // Generate using templates |
| try { |
| generateUsingTemplates(monitor, pack); |
| } catch (Exception e) { |
| return WTPCommonPlugin.createErrorStatus(e.toString()); |
| } |
| return OK_STATUS; |
| } |
| |
| /** |
| * This method will return the java package as specified by the new java |
| * class data model. If the package does not exist, it will create the |
| * package. This method should not return null. |
| * |
| * @see INewJavaClassDataModelProperties#JAVA_PACKAGE |
| * @see IPackageFragmentRoot#createPackageFragment(java.lang.String, |
| * boolean, org.eclipse.core.runtime.IProgressMonitor) |
| * |
| * @return IPackageFragment the java package |
| */ |
| protected final IPackageFragment createJavaPackage() { |
| // Retrieve the package name from the java class data model |
| String packageName = model.getStringProperty(INewJavaClassDataModelProperties.JAVA_PACKAGE); |
| IPackageFragmentRoot packRoot = (IPackageFragmentRoot) model |
| .getProperty(INewJavaClassDataModelProperties.JAVA_PACKAGE_FRAGMENT_ROOT); |
| IPackageFragment pack = packRoot.getPackageFragment(packageName); |
| // Handle default package |
| if (pack == null) { |
| pack = packRoot.getPackageFragment(""); //$NON-NLS-1$ |
| } |
| // Create the package fragment if it does not exist |
| if (!pack.exists()) { |
| String packName = pack.getElementName(); |
| try { |
| pack = packRoot.createPackageFragment(packName, true, null); |
| } catch (JavaModelException e) { |
| Logger.getLogger().log(e); |
| } |
| } |
| // Return the package |
| return pack; |
| } |
| |
| /** |
| * Subclasses may extend this method to provide their own template based |
| * creation of an annotated servlet java class file. This implementation |
| * uses the creation of a CreateServletTemplateModel and the WTPJetEmitter |
| * to create the java class with the annotated tags. This method accepts |
| * null for monitor, it does not accept null for fragment. If annotations |
| * are not being used the tags will be omitted from the class. |
| * |
| * @see CreateServletTemplateModel |
| * @see NewServletClassOperation#generateTemplateSource(CreateServletTemplateModel, |
| * IProgressMonitor) |
| * |
| * @param monitor |
| * @param fragment |
| * @throws CoreException |
| * @throws WFTWrappedException |
| */ |
| protected void generateUsingTemplates(IProgressMonitor monitor, IPackageFragment fragment) throws WFTWrappedException, CoreException { |
| // Create the servlet template model |
| CreateServletTemplateModel tempModel = createTemplateModel(); |
| IProject project = getTargetProject(); |
| String source; |
| // Using the WTPJetEmitter, generate the java source based on the |
| // servlet template model |
| try { |
| source = generateTemplateSource(tempModel, monitor); |
| } catch (Exception e) { |
| throw new WFTWrappedException(e); |
| } |
| if (fragment != null) { |
| // Create the java file |
| String javaFileName = tempModel.getServletClassName() + DOT_JAVA; |
| ICompilationUnit cu = fragment.getCompilationUnit(javaFileName); |
| // Add the compilation unit to the java file |
| if (cu == null || !cu.exists()) |
| cu = fragment.createCompilationUnit(javaFileName, source, true, monitor); |
| IFile aFile = (IFile) cu.getResource(); |
| // Let the annotations controller process the annotated resource |
| AnnotationsController controller = AnnotationsControllerManager.INSTANCE.getAnnotationsController(project); |
| if (controller != null) |
| controller.process(aFile); |
| // ((J2EEEditModel)model.getEditModel()).getWorkingCopy(cu, true); |
| // //Track CU. |
| } |
| // Add the annotations builder to the java project so metadata can be |
| // generated. |
| // TODO for M4 cannot add builder directly here, needs to be set up more |
| // extensibly |
| addAnnotationsBuilder(monitor, project); |
| } |
| |
| /** |
| * This method is intended for internal use only. This method will add the |
| * annotations builder for Xdoclet to the targetted project. This needs to |
| * be removed from the operation and set up to be more extensible throughout |
| * the workbench. |
| * |
| * @see NewServletClassOperation#generateUsingTemplates(IProgressMonitor, |
| * IPackageFragment) |
| * |
| * |
| */ |
| private void addAnnotationsBuilder(IProgressMonitor monitor, IProject project) { |
| // If an extended annotations processor is added, ignore the default |
| // xdoclet one |
| Descriptor descriptor = AnnotationsControllerManager.INSTANCE.getDescriptor(getTargetComponent().getProject()); |
| if (descriptor != null) |
| return; |
| try { |
| // Add the xdoclet facet. |
| // |
| |
| installXDocletFacet(monitor, project); |
| |
| } catch (Exception e) { |
| // Ignore |
| } |
| } |
| |
| /** |
| * This method is intended for internal use only. This will add an webdoclet |
| * facet to the project. |
| * @throws CoreException |
| * @throws ExecutionException |
| * |
| */ |
| private void installXDocletFacet(IProgressMonitor monitor, IProject project) throws CoreException, ExecutionException { |
| |
| IFacetedProject facetedProject = ProjectFacetsManager.create(project); |
| Set facets = facetedProject.getProjectFacets(); |
| Set fixedFacets = facetedProject.getFixedProjectFacets(); |
| boolean shouldInstallFacet = true; |
| for (Iterator iter = facets.iterator(); iter.hasNext();) { |
| IProjectFacetVersion facetVersion = (IProjectFacetVersion) iter.next(); |
| String facetID = facetVersion.getProjectFacet().getId(); |
| if (JST_WEB_XDOCLET.equals(facetID)) { |
| shouldInstallFacet = false; |
| } |
| } |
| if (!shouldInstallFacet) |
| return; |
| |
| IDataModel dm = DataModelFactory.createDataModel(new FacetInstallDataModelProvider()); |
| dm.setProperty(IFacetDataModelProperties.FACET_ID, JST_WEB_XDOCLET); |
| dm.setProperty(IFacetDataModelProperties.FACET_PROJECT_NAME, project.getName()); |
| dm.setProperty(IFacetDataModelProperties.FACET_VERSION_STR, JST_WEB_XDOCLET_VERSION); //$NON-NLS-1$ |
| IDataModel fdm = DataModelFactory.createDataModel(new FacetProjectCreationDataModelProvider()); |
| fdm.setProperty(IFacetProjectCreationDataModelProperties.FACET_PROJECT_NAME, project.getName()); |
| |
| FacetDataModelMap map = (FacetDataModelMap) fdm.getProperty(IFacetProjectCreationDataModelProperties.FACET_DM_MAP); |
| map.add(dm); |
| |
| fdm.getDefaultOperation().execute(monitor, null); |
| facetedProject.setFixedProjectFacets(fixedFacets); |
| |
| } |
| |
| /** |
| * This method is intended for internal use only. This will use the |
| * WTPJETEmitter to create an annotated java file based on the passed in |
| * servlet class template model. This method does not accept null |
| * parameters. It will not return null. If annotations are not used, it will |
| * use the non annotated template to omit the annotated tags. |
| * |
| * @see NewServletClassOperation#generateUsingTemplates(IProgressMonitor, |
| * IPackageFragment) |
| * @see JETEmitter#generate(org.eclipse.core.runtime.IProgressMonitor, |
| * java.lang.Object[]) |
| * @see CreateServletTemplateModel |
| * |
| * @param tempModel |
| * @param monitor |
| * @return String the source for the java file |
| * @throws JETException |
| */ |
| private String generateTemplateSource(CreateServletTemplateModel tempModel, IProgressMonitor monitor) throws JETException { |
| URL templateURL = null; |
| // If annotated, use annotated template |
| if (model.getBooleanProperty(IAnnotationsDataModel.USE_ANNOTATIONS)) |
| templateURL = WebPlugin.getDefault().find( |
| new Path(TEMPLATE_DIR + getDataModel().getStringProperty(INewServletClassDataModelProperties.TEMPLATE_FILE))); |
| // Otherwise use non annotated template |
| else |
| templateURL = WebPlugin.getDefault().find( |
| new Path(TEMPLATE_DIR |
| + getDataModel().getStringProperty(INewServletClassDataModelProperties.NON_ANNOTATED_TEMPLATE_FILE))); |
| cleanUpOldEmitterProject(); |
| WTPJETEmitter emitter = new WTPJETEmitter(templateURL.toString(), this.getClass().getClassLoader()); |
| emitter.setIntelligentLinkingEnabled(true); |
| emitter.addVariable(WEB_PLUGIN, WebPlugin.PLUGIN_ID); |
| return emitter.generate(monitor, new Object[] { tempModel }); |
| } |
| |
| private void cleanUpOldEmitterProject() { |
| IProject project = ProjectUtilities.getProject(WTPJETEmitter.PROJECT_NAME); |
| if (project == null || !project.exists()) |
| return; |
| try { |
| IMarker[] markers = project.findMarkers(IJavaModelMarker.BUILDPATH_PROBLEM_MARKER, false, IResource.DEPTH_ZERO); |
| for (int i = 0, l = markers.length; i < l; i++) { |
| if (((Integer) markers[i].getAttribute(IMarker.SEVERITY)).intValue() == IMarker.SEVERITY_ERROR) { |
| project.delete(true, new NullProgressMonitor()); |
| break; |
| } |
| } |
| } catch (Exception e) { |
| e.printStackTrace(); |
| } |
| } |
| |
| /** |
| * This method is intended for internal use only. This method will create an |
| * instance of the CreateServletTemplate model to be used in conjunction |
| * with the WTPJETEmitter. This method will not return null. |
| * |
| * @see CreateServletTemplateModel |
| * @see NewServletClassOperation#generateUsingTemplates(IProgressMonitor, |
| * IPackageFragment) |
| * |
| * @return CreateServletTemplateModel |
| */ |
| private CreateServletTemplateModel createTemplateModel() { |
| // Create the CreateServletTemplateModel instance with the new servlet |
| // class data model |
| CreateServletTemplateModel templateModel = new CreateServletTemplateModel(model); |
| return templateModel; |
| } |
| |
| /** |
| * This method will return the java source folder as specified in the java |
| * class data model. It will create the java source folder if it does not |
| * exist. This method may return null. |
| * |
| * @see INewJavaClassDataModelProperties#SOURCE_FOLDER |
| * @see IFolder#create(boolean, boolean, |
| * org.eclipse.core.runtime.IProgressMonitor) |
| * |
| * @return IFolder the java source folder |
| */ |
| protected final IFolder createJavaSourceFolder() { |
| // Get the source folder name from the data model |
| String folderFullPath = model.getStringProperty(INewJavaClassDataModelProperties.SOURCE_FOLDER); |
| IWorkspaceRoot root = ResourcesPlugin.getWorkspace().getRoot(); |
| IFolder folder = root.getFolder(new Path(folderFullPath)); |
| // If folder does not exist, create the folder with the specified path |
| if (!folder.exists()) { |
| try { |
| folder.create(true, true, null); |
| } catch (CoreException e) { |
| Logger.getLogger().log(e); |
| } |
| } |
| // Return the source folder |
| return folder; |
| } |
| } |