blob: e82843423961b5ac808f80ead5f58e34fc884bd3 [file] [log] [blame]
/*
* 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;
}
}
}