/*******************************************************************************
* Copyright (c) 2007 Exadel, Inc. and Red Hat, Inc.
* Distributed under license by Red Hat, Inc. All rights reserved.
* This program is 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:
* Exadel, Inc. and Red Hat, Inc. - initial API and implementation
******************************************************************************/
package org.jboss.tools.jsf.model.pv;
import java.util.*;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.runtime.CoreException;
import org.jboss.tools.common.model.java.handlers.OpenJavaSourceHandler;
import org.eclipse.jdt.core.IMember;
import org.eclipse.jdt.core.IType;
import org.jboss.tools.common.meta.action.XActionInvoker;
import org.jboss.tools.common.model.*;
import org.jboss.tools.common.model.util.EclipseJavaUtil;
import org.jboss.tools.common.model.util.EclipseResourceUtil;
import org.jboss.tools.common.model.util.XModelObjectLoaderUtil;
import org.jboss.tools.jsf.model.JSFConstants;
import org.jboss.tools.jsf.model.JSFELCompletionEngine;
import org.jboss.tools.jsf.model.JSFXModelUtil;
import org.jboss.tools.jsf.model.helpers.converter.*;
import org.jboss.tools.jsf.model.helpers.pages.OpenCaseHelper;
import org.jboss.tools.jsf.model.helpers.pages.ResourceBundleHelper;
import org.jboss.tools.jsf.project.JSFNature;
import org.jboss.tools.jsf.web.JSFWebProject;
import org.jboss.tools.jsf.web.pattern.JSFUrlPattern;
import org.jboss.tools.jst.web.model.helpers.WebAppHelper;
import org.jboss.tools.jst.web.model.pv.WebProjectNode;
import org.jboss.tools.jst.web.project.WebProject;
import org.jboss.tools.jst.web.project.list.IWebPromptingProvider;
public class JSFPromptingProvider implements IWebPromptingProvider {
static Set<String> SUPPORTED_IDS = new HashSet<String>();
static {
SUPPORTED_IDS.add(JSF_BUNDLES);
SUPPORTED_IDS.add(JSF_REGISTERED_BUNDLES);
SUPPORTED_IDS.add(JSF_BUNDLE_PROPERTIES);
SUPPORTED_IDS.add(JSF_MANAGED_BEANS);
SUPPORTED_IDS.add(JSF_BEAN_PROPERTIES);
SUPPORTED_IDS.add(JSF_BEAN_METHODS);
SUPPORTED_IDS.add(JSF_BEAN_ADD_PROPERTY);
SUPPORTED_IDS.add(JSF_VIEW_ACTIONS);
SUPPORTED_IDS.add(JSF_BEAN_OPEN);
SUPPORTED_IDS.add(JSF_GET_PATH);
SUPPORTED_IDS.add(JSF_OPEN_ACTION);
SUPPORTED_IDS.add(JSF_OPEN_CONVERTOR);
SUPPORTED_IDS.add(JSF_OPEN_VALIDATOR);
SUPPORTED_IDS.add(JSF_OPEN_RENDER_KIT);
SUPPORTED_IDS.add(JSF_OPEN_CLASS_PROPERTY);
SUPPORTED_IDS.add(JSF_OPEN_TAG_LIBRARY);
SUPPORTED_IDS.add(JSF_OPEN_BUNDLE);
SUPPORTED_IDS.add(JSF_OPEN_KEY);
SUPPORTED_IDS.add(JSF_GET_URL);
SUPPORTED_IDS.add(JSF_CONVERT_URL_TO_PATH);
SUPPORTED_IDS.add(JSF_GET_TAGLIBS);
SUPPORTED_IDS.add(JSF_CONVERTER_IDS);
SUPPORTED_IDS.add(JSF_VALIDATOR_IDS);
SUPPORTED_IDS.add(JSF_FACES_CONFIG);
}
public final static String PROVIDER_ID = "jsf"; //$NON-NLS-1$
public boolean isSupporting(String id) {
return id != null && SUPPORTED_IDS.contains(id);
}
public List<Object> getList(XModel model, String id, String prefix, Properties properties) {
try {
return getListInternal(model, id, prefix, properties);
} catch (CoreException e) {
if(properties != null) {
String message = e.getMessage();
if(message==null) {
message = e.getClass().getName();
}
properties.setProperty(ERROR, message);
}
return EMPTY_LIST;
}
}
private List<Object> getListInternal(XModel model, String id, String prefix, Properties properties) throws CoreException {
String error = null;
if(JSF_BUNDLES.equals(id)) return getBundles(model);
if(JSF_REGISTERED_BUNDLES.equals(id)) {
return ResourceBundleHelper.getRegisteredResourceBundles(model);
}
if(JSF_BUNDLE_PROPERTIES.equals(id)) return getBundleProperties(model, prefix);
if(JSF_MANAGED_BEANS.equals(id)) return getBeans(model);
if(JSF_BEAN_PROPERTIES.equals(id)) {
String type = (properties == null) ? null : properties.getProperty(PROPERTY_TYPE);
String sBeanOnly = (properties == null) ? null : properties.getProperty(PROPERTY_BEAN_ONLY);
boolean beanOnly = "true".equals(sBeanOnly); //$NON-NLS-1$
return getBeanProperties(model, prefix, type, beanOnly);
} else if(JSF_BEAN_METHODS.equals(id)) {
String[] parameterTypes = (String[])properties.get(PARAMETER_TYPES);
String returnType = properties.getProperty(RETURN_TYPE);
return getBeanMethods(model, prefix, parameterTypes, returnType);
} else if(JSF_BEAN_ADD_PROPERTY.equals(id)) {
XModelObject property = addPropertyToBean(model, prefix);
if(property == null) return EMPTY_LIST;
ArrayList<Object> list = new ArrayList<Object>();
list.add(property);
return list;
} else if(JSF_VIEW_ACTIONS.equals(id)) {
String viewPath = properties.getProperty(VIEW_PATH);
return getViewActions(model, viewPath);
} else if(JSF_BEAN_OPEN.equals(id)) {
openBean(model, prefix);
} else if(JSF_GET_PATH.equals(id)) {
return getPathAsList(model, prefix);
} else if(JSF_OPEN_ACTION.equals(id)) {
IFile file = (IFile)properties.get(FILE);
String action = prefix;
OpenCaseHelper h = new OpenCaseHelper();
error = h.run(model, file, action);
} else if(JSF_OPEN_CONVERTOR.equals(id)) {
String converterId = prefix;
OpenConverterHelper h = new OpenConverterHelper();
error = h.run(model, converterId);
} else if(JSF_OPEN_VALIDATOR.equals(id)) {
String validatorId = prefix;
OpenValidatorHelper h = new OpenValidatorHelper();
error = h.run(model, validatorId);
} else if(JSF_OPEN_RENDER_KIT.equals(id)) {
String renderkitId = prefix;
OpenRenderKitHelper h = new OpenRenderKitHelper();
error = h.run(model, renderkitId);
} else if(JSF_OPEN_CLASS_PROPERTY.equals(id)) {
OpenJavaSourceHandler.open(model, prefix, properties);
} else if(JSF_OPEN_TAG_LIBRARY.equals(id)) {
String uri = prefix;
String tagName = properties.getProperty(NAME);
String attributeName = properties.getProperty(ATTRIBUTE);
OpenTagLib h = new OpenTagLib();
error = h.run(model, uri, tagName, attributeName);
} else if(JSF_OPEN_BUNDLE.equals(id)) {
String bundle = properties.getProperty(BUNDLE);
String locale = properties.getProperty(LOCALE);
OpenKeyHelper h = new OpenKeyHelper();
error = h.run(model, bundle, locale);
} else if(JSF_OPEN_KEY.equals(id)) {
String bundle = properties.getProperty(BUNDLE);
String key = properties.getProperty(KEY);
String locale = properties.getProperty(LOCALE);
OpenKeyHelper h = new OpenKeyHelper();
error = h.run(model, bundle, key, locale);
} else if(JSF_GET_URL.equals(id)) {
if(!EclipseResourceUtil.hasNature(model, JSFNature.NATURE_ID)) return EMPTY_LIST;
ArrayList<Object> list = new ArrayList<Object>();
String url = JSFWebProject.getInstance(model).getUrlPattern().getJSFUrl(prefix);
if(url != null && url.length() > 0) list.add(url);
return list;
} else if(JSF_CONVERT_URL_TO_PATH.equals(id)) {
if(!EclipseResourceUtil.hasNature(model, JSFNature.NATURE_ID)) {
XModelObject webxml = WebAppHelper.getWebApp(model);
if(webxml != null) {
JSFWebProject.getInstance(model).getPatternLoader().revalidate(webxml);
} else {
return EMPTY_LIST;
}
}
ArrayList<Object> list = new ArrayList<Object>();
List<String> paths = JSFWebProject.getInstance(model).getUrlPattern().getJSFPaths(prefix);
if(!paths.isEmpty()) {
list.addAll(paths);
} else {
String path = JSFWebProject.getInstance(model).getUrlPattern().getJSFPath(prefix);
if(path != null && path.length() > 0) list.add(path);
}
return list;
} else if(JSF_GET_TAGLIBS.equals(id)) {
ArrayList<Object> list = new ArrayList<Object>();
WebProject p = WebProject.getInstance(model);
Map<String,XModelObject> map = p.getTaglibMapping().getTaglibObjects();
list.addAll(map.keySet());
return list;
} else if(JSF_CONVERTER_IDS.equals(id)) {
return new OpenConverterHelper().getConverterIDs(model);
} else if(JSF_VALIDATOR_IDS.equals(id)) {
return new OpenValidatorHelper().getValidatorIDs(model);
} else if(JSF_FACES_CONFIG.equals(id)) {
XModelObject fc = findFacesConfig(model);
if(fc == null) return EMPTY_LIST;
ArrayList<Object> list = new ArrayList<Object>();
list.add(fc);
return list;
}
if(error != null) throw new XModelException(error);
return EMPTY_LIST;
}
public List<Object> getBundles(XModel model) {
JSFProjectsRoot root = JSFProjectsTree.getProjectsRoot(model);
if(root == null) return EMPTY_LIST;
WebProjectNode n = (WebProjectNode)root.getChildByPath(JSFProjectTreeConstants.RESOURCE_BUNDLES);
if(n == null) return EMPTY_LIST;
XModelObject[] os = n.getTreeChildren();
List<Object> list = new ArrayList<Object>();
for (int i = 0; i < os.length; i++) {
String p = XModelObjectLoaderUtil.getResourcePath(os[i]);
if(p == null || !p.endsWith(".properties")) continue; //$NON-NLS-1$
p = p.substring(1, p.length() - 11).replace('/', '.');
list.add(p);
}
return list;
}
public List<Object> getBundleProperties(XModel model, String bundle) {
if(bundle == null || bundle.length() == 0) return EMPTY_LIST;
OpenKeyHelper helper = new OpenKeyHelper();
XModelObject[] bundleObjects = helper.findBundles(model, bundle, null);
if (bundleObjects == null)
return EMPTY_LIST;
// XModelObject b = model.getByPath("/" + bundle.replace('.', '/') + ".properties");
Set properties = new TreeSet(String.CASE_INSENSITIVE_ORDER);
for (XModelObject b : bundleObjects) {
if(b == null) continue;
XModelObject[] os = b.getChildren();
for (int i = 0; i < os.length; i++) {
// list.add(os[i].getAttributeValue("name"));
properties.add(os[i].getAttributeValue("name"));
}
}
List<Object> list = new ArrayList<Object>();
list.addAll(properties);
return list;
}
public List<Object> getBeans(XModel model) {
JSFProjectsRoot root = JSFProjectsTree.getProjectsRoot(model);
if(root == null) return EMPTY_LIST;
WebProjectNode n = (WebProjectNode)root.getChildByPath(JSFProjectTreeConstants.CONFIGURATION);
if(n == null) return EMPTY_LIST;
List<Object> list = new ArrayList<Object>();
for (XModelObject o: n.getTreeChildren()) {
if(!JSFXModelUtil.isFacesConfig(o)) continue;
getBeans(o, BeanConstants.MANAGED_BEAN_CONSTANTS, list);
getBeans(o, BeanConstants.REFERENCED_BEAN_CONSTANTS, list);
}
return list;
}
private void getBeans(XModelObject o, BeanConstants constants, List<Object> list) {
XModelObject mb = o.getChildByPath(constants.folder);
if(mb == null) return;
XModelObject[] bs = mb.getChildren();
for (int j = 0; j < bs.length; j++) {
list.add(bs[j].getAttributeValue(constants.nameAttribute));
}
}
public List<JSFELCompletionEngine.IJSFVariable> getVariables(XModel model) {
List<JSFELCompletionEngine.IJSFVariable> result = new ArrayList<JSFELCompletionEngine.IJSFVariable>();
JSFProjectsRoot root = JSFProjectsTree.getProjectsRoot(model);
if(root == null) return result;
WebProjectNode n = (WebProjectNode)root.getChildByPath(JSFProjectTreeConstants.CONFIGURATION);
WebProjectNode beans = (WebProjectNode)root.getChildByPath(JSFProjectTreeConstants.BEANS);
for (XModelObject o: n.getTreeChildren()) {
if(!JSFXModelUtil.isFacesConfig(o)) continue;
getVariables(o, BeanConstants.MANAGED_BEAN_CONSTANTS, beans, result);
getVariables(o, BeanConstants.REFERENCED_BEAN_CONSTANTS, beans, result);
}
return result;
}
private void getVariables(XModelObject o, BeanConstants constants, WebProjectNode beans, List<JSFELCompletionEngine.IJSFVariable> list) {
XModelObject mb = o.getChildByPath(constants.folder);
if(mb == null) return;
XModelObject[] bs = mb.getChildren();
for (XModelObject q : bs) {
final String name = q.getAttributeValue(constants.nameAttribute);
String className = q.getAttributeValue(constants.classAttribute);
XModelObject c = findBeanClassByClassName(beans, className);
if (c instanceof JSFProjectBean) {
JSFProjectBean b = (JSFProjectBean) c;
final IType type = b.getType();
JSFELCompletionEngine.IJSFVariable var = new JSFELCompletionEngine.IJSFVariable() {
public IMember getSourceMember() {
return type;
}
public String getName() {
return name;
}
};
list.add(var);
}
}
}
public List<Object> getBeanProperties(XModel model, String prefix, String type, boolean beanOnly) {
if(prefix.length() == 0) return EMPTY_LIST;
JSFProjectsRoot root = JSFProjectsTree.getProjectsRoot(model);
if(root == null) return EMPTY_LIST;
IProject project = EclipseResourceUtil.getProject(root);
int d = prefix.indexOf('.');
String beanName = (d < 0) ? prefix : prefix.substring(0, d);
String property = (d < 0) ? null : prefix.substring(d + 1);
WebProjectNode n = (WebProjectNode)root.getChildByPath(JSFProjectTreeConstants.BEANS);
WebProjectNode conf = (WebProjectNode)root.getChildByPath(JSFProjectTreeConstants.CONFIGURATION);
if(n == null || conf == null) return EMPTY_LIST;
XModelObject bean = findBean(conf, beanName);
if(bean == null) return EMPTY_LIST;
List<Object> list = new ArrayList<Object>();
XModelObject beanClass = findBeanClass(n, bean);
if(beanClass == null) {
if(property.length() > 0) return EMPTY_LIST;
XModelObject[] cs = bean.getChildren("JSFManagedProperty");
for (int i = 0; i < cs.length; i++) {
String cn = cs[i].getAttributeValue("property-class");
if(type != null && !EclipseJavaUtil.isDerivedClass(cn, type, project)) continue;
if(beanOnly && isNotBean(cn)) continue;
list.add(cs[i].getAttributeValue("property-name"));
}
} else {
if(property != null && property.length() > 0) beanClass = beanClass.getChildByPath(property.replace('.', '/'));
if(beanClass == null) return EMPTY_LIST;
XModelObject[] os = beanClass.getChildren("JSFProjectBeanProperty");
for (int i = 0; i < os.length; i++) {
String cn = os[i].getAttributeValue("class name");
if(type != null && !EclipseJavaUtil.isDerivedClass(cn, type, project)) continue;
if(beanOnly && isNotBean(cn)) continue;
list.add(os[i].getAttributeValue("name"));
}
}
return list;
}
private boolean isNotBean(String cn) {
if(cn == null || cn.length() == 0) return true;
if(JSFProjectBeans.primitive.indexOf("!" + cn + "!") >= 0) return true;
if(cn.startsWith("java.lang.")) return true;
if(cn.startsWith("java.util.")) return true;
return false;
}
/**
* Called by ui that requested list of beans.
* @param model
* @param bean
* @return
*/
private XModelObject addPropertyToBean(XModel model, String beanName) {
JSFProjectsRoot root = JSFProjectsTree.getProjectsRoot(model);
WebProjectNode conf = (WebProjectNode)root.getChildByPath(JSFProjectTreeConstants.CONFIGURATION);
XModelObject bean = findBean(conf, beanName);
if(bean == null) return null;
Properties p = new Properties();
XActionInvoker.invoke("CreateActions.CreateProperty", bean, p);
return (XModelObject)p.get("created");
}
/**
* Creates bean for any class.
* Returns list of property names
* @param model
* @param className
* @param type
* @return
*/
public List buildBeanProperties(XModel model, String className, String type) {
JSFProjectBean beanClass = buildBean(model, className);
if(beanClass == null) return EMPTY_LIST;
IProject project = EclipseResourceUtil.getProject(beanClass);
ArrayList<Object> list = new ArrayList<Object>();
XModelObject[] os = beanClass.getChildren("JSFProjectBeanProperty");
for (int i = 0; i < os.length; i++) {
if(type == null ||
EclipseJavaUtil.isDerivedClass(os[i].getAttributeValue("class name"), type, project)
) {
list.add(os[i].getAttributeValue("name"));
}
}
return list;
}
public static JSFProjectBean buildBean(XModel model, String className) {
JSFProjectsRoot root = JSFProjectsTree.getProjectsRoot(model);
if(root == null) return null;
JSFProjectBeans n = (JSFProjectBeans)root.getChildByPath(JSFProjectTreeConstants.BEANS);
IType cls = n.getType(className);
if(cls == null) return null;
JSFProjectBean beanClass = (JSFProjectBean)model.createModelObject("JSFProjectBean", null);
beanClass.setBeans(n);
beanClass.setType(cls);
beanClass.setAttributeValue("class name", className);
return beanClass;
}
private boolean openBean(XModel model, String prefix) {
if(prefix.length() == 0) return false;
JSFProjectsRoot root = JSFProjectsTree.getProjectsRoot(model);
if(root == null) return false;
JSFBeanSearcher s = new JSFBeanSearcher(model);
s.parse(prefix);
XModelObject bean = s.getBeanClass();
String property = s.getProperty();
if(bean == null) return false;
Properties p = new Properties();
if(property != null) {
p.setProperty("property", property);
}
if(bean != null) XActionInvoker.invoke("Open", bean, p);
return true;
}
static XModelObject findBean(WebProjectNode conf, String beanName) {
XModelObject[] os = conf.getTreeChildren();
for (int i = 0; i < os.length; i++) {
if(!JSFXModelUtil.isFacesConfig(os[i])) continue;
XModelObject bean = os[i].getChildByPath("Managed Beans/" + beanName);
if(bean != null) return bean;
bean = os[i].getChildByPath("Referenced Beans/" + beanName);
if(bean != null) return bean;
}
return null;
}
static XModelObject findBeanClass(WebProjectNode beans, XModelObject bean) {
BeanConstants constants = BeanConstants.getConstants(bean);
if(constants == null) return null;
String className = bean.getAttributeValue(constants.classAttribute);
return findBeanClassByClassName(beans, className);
}
static XModelObject findBeanClassByClassName(WebProjectNode beans, String className) {
if(beans == null) return null;
XModelObject[] os = beans.getTreeChildren();
for (int i = 0; i < os.length; i++) {
if(className.equals(os[i].getAttributeValue("class name"))) return os[i];
}
return null;
}
public List<Object> getBeanMethods(XModel model, String prefix, String[] parameterTypes, String returnType) {
if(prefix.length() == 0) return EMPTY_LIST;
JSFProjectsRoot root = JSFProjectsTree.getProjectsRoot(model);
if(root == null) return EMPTY_LIST;
int d = prefix.indexOf('.');
String beanName = (d < 0) ? prefix : prefix.substring(0, d);
String property = (d < 0) ? null : prefix.substring(d + 1);
WebProjectNode n = (WebProjectNode)root.getChildByPath(JSFProjectTreeConstants.BEANS);
WebProjectNode conf = (WebProjectNode)root.getChildByPath(JSFProjectTreeConstants.CONFIGURATION);
if(n == null || conf == null) return EMPTY_LIST;
XModelObject bean = findBean(conf, beanName);
if(bean == null) return EMPTY_LIST;
List<Object> list = new ArrayList<Object>();
XModelObject beanClass = findBeanClass(n, bean);
if(beanClass == null) return EMPTY_LIST;
if(property != null && property.length() > 0) beanClass = beanClass.getChildByPath(property.replace('.', '/'));
if(beanClass == null) return EMPTY_LIST;
XModelObject[] os = beanClass.getChildren("JSFProjectBeanMethod");
for (int i = 0; i < os.length; i++) {
JSFProjectBeanMember bm = (JSFProjectBeanMember)os[i];
if(returnType == null || bm.hasMethodSignature(returnType, parameterTypes)) {
list.add(os[i].getAttributeValue("name"));
}
}
return list;
}
public List<Object> getViewActions(XModel model, String viewPath) {
if(viewPath == null) return EMPTY_LIST;
JSFProjectsRoot root = JSFProjectsTree.getProjectsRoot(model);
if(root == null) return EMPTY_LIST;
WebProjectNode n = (WebProjectNode)root.getChildByPath(JSFProjectTreeConstants.CONFIGURATION);
if(n == null) return EMPTY_LIST;
XModelObject[] os = n.getTreeChildren();
List<Object> list = new ArrayList<Object>();
for (int i = 0; i < os.length; i++) {
XModelObject r = os[i].getChildByPath(JSFConstants.FOLDER_NAVIGATION_RULES);
if(r == null) continue;
XModelObject[] rs = r.getChildren();
for (int j = 0; j < rs.length; j++) {
if(!OpenCaseHelper.isPatternMatches(rs[j].getAttributeValue(JSFConstants.ATT_FROM_VIEW_ID), viewPath)) continue;
XModelObject[] cs = rs[j].getChildren();
for (int k = 0; k < cs.length; k++) {
String q = cs[k].getAttributeValue(JSFConstants.ATT_FROM_OUTCOME);
if(!list.contains(q)) list.add(q);
}
}
}
return list;
}
//JSF_GET_PATH
List<Object> getPathAsList(XModel model, String url) {
/*
* Fixes https://jira.jboss.org/jira/browse/JBIDE-5577
* List will return all possible paths for url.
*/
List<Object> pathsList = new ArrayList<Object>();
JSFWebProject p = JSFWebProject.getInstance(model);
if(p == null) {
pathsList.add(url);
} else {
JSFUrlPattern pattern = p.getUrlPattern();
if (pattern != null) {
pathsList.addAll(pattern.getJSFPaths(url));
} else {
pathsList.add(url);
}
}
return pathsList;
}
String getPath(XModel model, String url) {
JSFWebProject p = JSFWebProject.getInstance(model);
if(p == null) {
return url;
}
JSFUrlPattern pattern = p.getUrlPattern();
return (pattern == null) ? url : pattern.getJSFPath(url);
}
public static XModelObject findFacesConfig(XModel model) {
XModelObject facesConfig = null;
JSFProjectsRoot root = JSFProjectsTree.getProjectsRoot(model);
if (root != null) {
WebProjectNode n = (WebProjectNode) root
.getChildByPath(JSFProjectTreeConstants.CONFIGURATION);
if (n != null) {
/*
* The array contains the all configuration files in the project
* including files from jar archives.
* Only editable object is be the necessary faces-config file.
*/
XModelObject[] os = n.getTreeChildren();
for (XModelObject o : os) {
if (o.isObjectEditable()) {
facesConfig = o;
break;
}
}
}
}
/*
* When nothing has been found try the last straight-forward way.
*/
if (facesConfig == null) {
facesConfig = model.getByPath("/faces-config.xml"); //$NON-NLS-1$
}
return facesConfig;
}
}