| /* |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you under the Apache License, Version 2.0 (the |
| * "License"); you may not use this file except in compliance |
| * with the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, |
| * software distributed under the License is distributed on an |
| * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| * KIND, either express or implied. See the License for the |
| * specific language governing permissions and limitations |
| * under the License. |
| */ |
| |
| package org.netbeans.modules.web.jsf.wizards; |
| |
| import java.io.IOException; |
| import java.net.URL; |
| import java.util.ArrayList; |
| import java.util.Collections; |
| import java.util.List; |
| import java.util.NoSuchElementException; |
| import java.util.Set; |
| import java.util.logging.Level; |
| import java.util.logging.Logger; |
| import javax.swing.JComponent; |
| import javax.swing.event.ChangeListener; |
| import org.netbeans.api.j2ee.core.Profile; |
| import org.netbeans.api.java.classpath.ClassPath; |
| import org.netbeans.api.project.FileOwnerQuery; |
| import org.netbeans.api.project.Project; |
| import org.netbeans.api.project.ProjectUtils; |
| import org.netbeans.api.project.SourceGroup; |
| import org.netbeans.api.project.Sources; |
| import org.netbeans.modules.j2ee.core.api.support.classpath.ContainerClassPathModifier; |
| import org.netbeans.modules.j2ee.dd.api.common.InitParam; |
| import org.netbeans.modules.j2ee.dd.api.web.DDProvider; |
| import org.netbeans.modules.j2ee.dd.api.web.WebApp; |
| import org.netbeans.modules.web.api.webmodule.WebModule; |
| import org.netbeans.modules.web.api.webmodule.WebProjectConstants; |
| import org.netbeans.modules.web.jsf.JSFCatalog; |
| import org.netbeans.modules.web.jsf.JSFConfigUtilities; |
| import org.netbeans.modules.web.jsf.JSFUtils; |
| import org.netbeans.modules.web.jsf.api.facesmodel.JSFVersion; |
| import static org.netbeans.modules.web.jsf.api.facesmodel.JSFVersion.JSF_1_0; |
| import static org.netbeans.modules.web.jsf.api.facesmodel.JSFVersion.JSF_1_1; |
| import static org.netbeans.modules.web.jsf.api.facesmodel.JSFVersion.JSF_1_2; |
| import static org.netbeans.modules.web.jsf.api.facesmodel.JSFVersion.JSF_2_0; |
| import static org.netbeans.modules.web.jsf.api.facesmodel.JSFVersion.JSF_2_1; |
| import static org.netbeans.modules.web.jsf.api.facesmodel.JSFVersion.JSF_2_2; |
| import static org.netbeans.modules.web.jsf.api.facesmodel.JSFVersion.JSF_3_0; |
| import org.netbeans.modules.web.wizards.Utilities; |
| import org.netbeans.spi.java.classpath.ClassPathProvider; |
| import org.netbeans.spi.project.ui.templates.support.Templates; |
| import org.openide.WizardDescriptor; |
| import org.openide.WizardDescriptor.Panel; |
| import org.openide.filesystems.FileObject; |
| import org.openide.filesystems.FileUtil; |
| import org.openide.filesystems.URLMapper; |
| import org.openide.loaders.DataFolder; |
| import org.openide.loaders.DataObject; |
| import org.openide.loaders.TemplateWizard; |
| import org.openide.util.Exceptions; |
| import org.openide.util.NbBundle; |
| import org.openide.util.NbBundle.Messages; |
| |
| /** |
| * A template wizard operator for new faces-config.xml |
| * |
| * @author Alexey Butenko |
| */ |
| public class FacesConfigIterator implements TemplateWizard.Iterator { |
| |
| private static final long serialVersionUID = 1L; |
| private static final Logger LOG = Logger.getLogger(FacesConfigIterator.class.getName()); |
| private static final String DEFAULT_NAME = "faces-config"; //NOI18N |
| private static final String FACES_CONFIG_PARAM = "javax.faces.CONFIG_FILES"; //NOI18N |
| private static final String JAKARTAEE_FACES_CONFIG_PARAM = "jakarta.faces.CONFIG_FILES"; //NOI18N |
| private static final String INIT_PARAM = "InitParam"; //NOI18N |
| private static final String RESOURCE_FOLDER = "/org/netbeans/modules/web/jsf/resources/"; //NOI18N |
| |
| private int index; |
| private transient WizardDescriptor.Panel[] panels; |
| |
| @Override |
| public Set<DataObject> instantiate(TemplateWizard wizard) throws IOException { |
| Project project = Templates.getProject( wizard ); |
| String targetName = Templates.getTargetName(wizard); |
| FileObject targetDir = Templates.getTargetFolder(wizard); |
| |
| FileObject fo = createFacesConfig(project, targetDir, targetName, true); |
| if (fo != null) { |
| return Collections.singleton(DataObject.find(fo)); |
| } else { |
| return Collections.EMPTY_SET; |
| } |
| } |
| |
| public static FileObject createFacesConfig(Project project, FileObject targetDir, String targetName, boolean addJSFFrameworkIfNecessary) throws IOException { |
| FileObject result = null; |
| WebModule wm = WebModule.getWebModule(project.getProjectDirectory()); |
| if (wm != null) { |
| FileObject docBase = wm.getDocumentBase(); |
| if (addJSFFrameworkIfNecessary) { |
| if (!JSFConfigUtilities.hasJsfFramework(docBase)) { |
| JSFConfigUtilities.extendJsfFramework(docBase, false); |
| } |
| |
| final ContainerClassPathModifier modifier = project.getLookup().lookup(ContainerClassPathModifier.class); |
| if (modifier != null) { |
| modifier.extendClasspath(targetDir, new String[] {ContainerClassPathModifier.API_JSF}); |
| } |
| } |
| |
| final String facesConfigTemplate = findFacesConfigTemplate(wm); |
| FileObject fcTemplate = URLMapper.findFileObject(FacesConfigIterator.class.getResource(RESOURCE_FOLDER + facesConfigTemplate)); |
| DataObject fc = DataObject.find(fcTemplate); |
| result = fc.createFromTemplate(DataFolder.findFolder(targetDir), targetName).getPrimaryFile(); //NOI18N |
| |
| FileObject dd = wm.getDeploymentDescriptor(); |
| // assert dd != null; |
| FileObject webInf = wm.getWebInf(); |
| WebApp ddRoot = (dd == null) ? null : DDProvider.getDefault().getDDRoot(dd); |
| |
| boolean isDefaultLocation = DEFAULT_NAME.equals(targetName) && targetDir == webInf; |
| if (!isDefaultLocation && ddRoot != null) { |
| try { |
| //Need to specify config file in javax.faces.FACES_CONFIG property |
| //First search existing param |
| InitParam[] parameters = ddRoot.getContextParam(); |
| boolean found = false; |
| int i = 0; |
| for (InitParam param : parameters) { |
| if (param.getParamName().equals(FACES_CONFIG_PARAM) || param.getParamName().equals(JAKARTAEE_FACES_CONFIG_PARAM)) { |
| found = true; |
| String value = param.getParamValue() + ",\n /" + FileUtil.getRelativePath(wm.getDocumentBase(), targetDir) + "/" + targetName + ".xml"; //NOI18N |
| ddRoot.removeContextParam(param); |
| InitParam newParameter = (InitParam) ddRoot.createBean(INIT_PARAM); |
| newParameter.setParamName(param.getParamName()); |
| newParameter.setParamValue(value); //NOI18N |
| ddRoot.addContextParam(newParameter); |
| break; |
| } |
| i++; |
| } |
| if (!found) { |
| InitParam contextParam = (InitParam) ddRoot.createBean(INIT_PARAM); |
| if(WebApp.VERSION_5_0.equals(ddRoot.getVersion())) { |
| contextParam.setParamName(JAKARTAEE_FACES_CONFIG_PARAM); |
| } else { |
| contextParam.setParamName(FACES_CONFIG_PARAM); |
| } |
| contextParam.setParamValue("/" + FileUtil.getRelativePath(wm.getDocumentBase(), targetDir) + "/" + targetName + ".xml"); //NOI18N |
| ddRoot.addContextParam(contextParam); |
| } |
| ddRoot.write(dd); |
| |
| } catch (ClassNotFoundException ex) { |
| Exceptions.printStackTrace(ex); |
| } |
| } |
| } |
| return result; |
| } |
| |
| private static ClassPath getCompileClasspath(Project project) { |
| ClassPathProvider cpp = project.getLookup().lookup(ClassPathProvider.class); |
| Sources sources = ProjectUtils.getSources(project); |
| if (sources == null) { |
| return null; |
| } |
| |
| SourceGroup[] sourceGroups = sources.getSourceGroups("java"); //NOII18N |
| if (sourceGroups.length > 0) { |
| return cpp.findClassPath(sourceGroups[0].getRootFolder(), ClassPath.COMPILE); |
| } |
| return null; |
| } |
| |
| private static String findFacesConfigTemplate(WebModule wm) { |
| JSFVersion jsfVersion = JSFVersion.get(wm, false); |
| // not found on project classpath (case of Maven project with JSF in deps) |
| if (jsfVersion == null) { |
| Profile profile = wm.getJ2eeProfile(); |
| if (profile.isAtLeast(Profile.JAKARTA_EE_9_WEB)) { |
| return JSFCatalog.RES_FACES_CONFIG_3_0; |
| } else if (profile.isAtLeast(Profile.JAVA_EE_8_WEB)) { |
| return JSFCatalog.RES_FACES_CONFIG_2_3; |
| } else if (profile.isAtLeast(Profile.JAVA_EE_7_WEB)) { |
| return JSFCatalog.RES_FACES_CONFIG_2_2; |
| } else if (profile.isAtLeast(Profile.JAVA_EE_6_WEB)) { |
| return JSFCatalog.RES_FACES_CONFIG_2_1; |
| } else if (profile.isAtLeast(Profile.JAVA_EE_5)) { |
| return JSFCatalog.RES_FACES_CONFIG_1_2; |
| } |
| |
| Project project = FileOwnerQuery.getOwner(JSFUtils.getFileObject(wm)); |
| if (project != null ) { |
| ClassPath compileClasspath = getCompileClasspath(project); |
| if (compileClasspath != null) { |
| List<URL> cpUrls = new ArrayList<>(); |
| for (ClassPath.Entry entry : compileClasspath.entries()) { |
| cpUrls.add(entry.getURL()); |
| } |
| jsfVersion = JSFVersion.forClasspath(cpUrls); |
| jsfVersion = jsfVersion == null ? JSFVersion.JSF_2_3 : jsfVersion; |
| return facesConfigForVersion(jsfVersion); |
| } |
| } |
| return JSFCatalog.RES_FACES_CONFIG_DEFAULT; |
| } |
| return facesConfigForVersion(jsfVersion); |
| } |
| |
| private static String facesConfigForVersion(JSFVersion jsfVersion) { |
| switch (jsfVersion) { |
| case JSF_3_0: |
| return JSFCatalog.RES_FACES_CONFIG_3_0; |
| case JSF_2_3: |
| return JSFCatalog.RES_FACES_CONFIG_2_3; |
| case JSF_2_2: |
| return JSFCatalog.RES_FACES_CONFIG_2_2; |
| case JSF_2_1: |
| return JSFCatalog.RES_FACES_CONFIG_2_1; |
| case JSF_2_0: |
| return JSFCatalog.RES_FACES_CONFIG_2_0; |
| case JSF_1_2: |
| return JSFCatalog.RES_FACES_CONFIG_1_2; |
| case JSF_1_1: |
| case JSF_1_0: |
| default: |
| return JSFCatalog.RES_FACES_CONFIG_DEFAULT; |
| } |
| } |
| |
| @Override |
| public void initialize(TemplateWizard wizard) { |
| // obtaining target folder |
| Project project = Templates.getProject( wizard ); |
| Sources sources = ProjectUtils.getSources(project); |
| SourceGroup[] sourceGroups = sources.getSourceGroups(WebProjectConstants.TYPE_WEB_INF); |
| |
| if (sourceGroups == null || sourceGroups.length == 0) { |
| sourceGroups = sources.getSourceGroups(WebProjectConstants.TYPE_DOC_ROOT); |
| } |
| |
| WizardDescriptor.Panel folderPanel; |
| if (sourceGroups == null || sourceGroups.length == 0) { |
| sourceGroups = sources.getSourceGroups(Sources.TYPE_GENERIC); |
| } |
| |
| folderPanel = new FacesConfigValidationPanel(Templates.buildSimpleTargetChooser(project, sourceGroups).create()); |
| panels = new WizardDescriptor.Panel[] { folderPanel }; |
| |
| // Creating steps. |
| Object prop = wizard.getProperty (WizardDescriptor.PROP_CONTENT_DATA); // NOI18N |
| String[] beforeSteps = null; |
| if (prop instanceof String[]) { |
| beforeSteps = (String[])prop; |
| } |
| String[] steps = Utilities.createSteps(beforeSteps, panels); |
| |
| for (int i = 0; i < panels.length; i++) { |
| JComponent jc = (JComponent)panels[i].getComponent (); |
| if (steps[i] == null) { |
| steps[i] = jc.getName (); |
| } |
| jc.putClientProperty (WizardDescriptor.PROP_CONTENT_SELECTED_INDEX, i); // NOI18N |
| jc.putClientProperty (WizardDescriptor.PROP_CONTENT_DATA, steps); // NOI18N |
| } |
| |
| WebModule wm = WebModule.getWebModule(project.getProjectDirectory()); |
| if (wm != null) { |
| FileObject webInf = wm.getWebInf(); |
| if (webInf == null) { |
| try { |
| FileObject documentBase = wm.getDocumentBase(); |
| if (documentBase == null) { |
| LOG.log(Level.INFO, "WebModule does not have valid documentBase"); |
| return; |
| } |
| webInf = FileUtil.createFolder(documentBase, "WEB-INF"); //NOI18N |
| } catch (IOException ex) { |
| Exceptions.printStackTrace(ex); |
| } |
| } |
| FileObject targetFolder = Templates.getTargetFolder(wizard); |
| String relativePath = (targetFolder == null) ? null : FileUtil.getRelativePath(webInf, targetFolder); |
| if (relativePath == null) { |
| Templates.setTargetFolder(wizard, webInf); |
| } |
| } |
| Templates.setTargetName(wizard, DEFAULT_NAME); |
| } |
| |
| @Override |
| public void uninitialize(TemplateWizard wiz) { |
| panels = null; |
| } |
| |
| @Override |
| public Panel<WizardDescriptor> current() { |
| return panels[index]; |
| } |
| |
| @Override |
| public String name() { |
| return NbBundle.getMessage(FacesConfigIterator.class, "TITLE_x_of_y", |
| index + 1, panels.length); |
| } |
| |
| @Override |
| public boolean hasNext() { |
| return index < panels.length - 1; |
| } |
| |
| @Override |
| public boolean hasPrevious() { |
| return index > 0; |
| } |
| |
| @Override |
| public void nextPanel() { |
| if (! hasNext ()) throw new NoSuchElementException (); |
| index++; |
| } |
| |
| @Override |
| public void previousPanel() { |
| if (! hasPrevious ()) throw new NoSuchElementException (); |
| index--; |
| } |
| |
| @Override |
| public void addChangeListener(ChangeListener l) { |
| } |
| |
| @Override |
| public void removeChangeListener(ChangeListener l) { |
| } |
| |
| private static class FacesConfigValidationPanel extends JSFValidationPanel { |
| |
| public FacesConfigValidationPanel(Panel delegate) { |
| super(delegate); |
| } |
| |
| @Messages({ |
| "FacesConfigIterator.err.no.document.base=Project hasn't defined document root. See project properties." |
| }) |
| @Override |
| public boolean isValid() { |
| if (!super.isValid()) { |
| return false; |
| } |
| |
| Project project = getProject(); |
| WebModule webModule = WebModule.getWebModule(project.getProjectDirectory()); |
| if (webModule != null && webModule.getDocumentBase() == null) { |
| getWizardDescriptor().putProperty(WizardDescriptor.PROP_WARNING_MESSAGE, Bundle.FacesConfigIterator_err_no_document_base()); |
| return true; |
| } |
| return true; |
| } |
| |
| } |
| |
| } |