/******************************************************************************* * Copyright (c) 2007-2011 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 * * Contributor: * Red Hat, Inc. - initial API and implementation ******************************************************************************/ package org.jboss.tools.seam.internal.core.el; import java.util.ArrayList; import java.util.Collection; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; import org.eclipse.core.resources.IFile; import org.eclipse.jdt.core.IJavaElement; import org.eclipse.jdt.core.IJavaProject; import org.eclipse.jdt.core.IMember; import org.eclipse.jdt.core.IType; import org.eclipse.jdt.core.JavaModelException; import org.eclipse.jface.text.BadLocationException; import org.jboss.tools.common.el.core.model.ELExpression; import org.jboss.tools.common.el.core.model.ELInstance; import org.jboss.tools.common.el.core.model.ELInvocationExpression; import org.jboss.tools.common.el.core.model.ELModel; import org.jboss.tools.common.el.core.parser.ELParser; import org.jboss.tools.common.el.core.parser.ELParserUtil; import org.jboss.tools.common.el.core.resolver.ELResolution; import org.jboss.tools.common.el.core.resolver.ELSegment; import org.jboss.tools.common.el.core.resolver.JavaMemberELSegmentImpl; import org.jboss.tools.common.el.core.resolver.TypeInfoCollector; import org.jboss.tools.common.el.core.resolver.TypeInfoCollector.MemberInfo; import org.jboss.tools.common.el.core.resolver.TypeInfoCollector.Type; import org.jboss.tools.common.el.core.resolver.TypeInfoCollector.TypeInfo; import org.jboss.tools.common.el.core.resolver.TypeInfoCollector.TypeMemberInfo; import org.jboss.tools.common.java.IJavaSourceReference; import org.jboss.tools.common.model.XModelObject; import org.jboss.tools.common.model.util.EclipseResourceUtil; import org.jboss.tools.seam.core.BijectedAttributeType; import org.jboss.tools.seam.core.IBijectedAttribute; import org.jboss.tools.seam.core.ISeamComponent; import org.jboss.tools.seam.core.ISeamComponentMethod; import org.jboss.tools.seam.core.ISeamContextShortVariable; import org.jboss.tools.seam.core.ISeamContextVariable; import org.jboss.tools.seam.core.ISeamElement; import org.jboss.tools.seam.core.ISeamJavaComponentDeclaration; import org.jboss.tools.seam.core.ISeamMessages; import org.jboss.tools.seam.core.ISeamProject; import org.jboss.tools.seam.core.ISeamXmlFactory; import org.jboss.tools.seam.core.SeamComponentMethodType; import org.jboss.tools.seam.core.SeamCorePlugin; /** * Utility class used to resolve Seam project variables and to get the methods/properties and their presentation strings from type * * @author Jeremy */ public class SeamExpressionResolver { /** * Returns Seam project variables which names start from specified value * * @param project * @param scope * @param name * @return */ public static List<ISeamContextVariable> resolveVariables(ISeamProject project, IFile context, String name, boolean onlyEqualNames) { if (project == null || name == null) return null; ISeamProject parent = project.getParentProject(); if(parent != null) { project = parent; } ISeamJavaComponentDeclaration declaration = null; if(context != null) { Set<ISeamComponent> cs = project.getComponentsByPath(context.getFullPath()); for (ISeamComponent c: cs) { ISeamJavaComponentDeclaration d = c.getJavaDeclaration(); if(d != null && context.getFullPath().equals(d.getSourcePath())) { declaration = d; } } } /* * JBIDE-670 scope isn't used anymore */ // return (scope == null ? internalResolveVariables(project, name, onlyEqualNames) : // internalResolveVariablesByScope(project, scope, name, onlyEqualNames)); return internalResolveVariables(project, declaration, name, onlyEqualNames); } /** * Returns Seam project variables which names start from specified value * No scope used * * @param project * @param name * @return */ private static List<ISeamContextVariable> internalResolveVariables(ISeamProject project, ISeamJavaComponentDeclaration context, String name, boolean onlyEqualNames) { //TODO add variables from imported packages Set<ISeamContextVariable> variables = project.getVariables(context); return internalResolveVariables(project, context, name, onlyEqualNames, variables); } private static List<ISeamContextVariable> internalResolveVariables(ISeamProject project, ISeamJavaComponentDeclaration context, String name, boolean onlyEqualNames, Set<ISeamContextVariable> variables) { List<ISeamContextVariable> resolvedVariables = new ArrayList<ISeamContextVariable>(); if(onlyEqualNames) { if(context != null) { variables = context.getVariablesByName(name); } else variables = new HashSet<ISeamContextVariable>(); if(variables.isEmpty()) { variables = project.getVariablesByName(name); } if(variables != null) resolvedVariables.addAll(variables); return resolvedVariables; } for (ISeamContextVariable variable : variables) { String n = variable.getName(); if (n.startsWith(name)) { resolvedVariables.add(variable); } } return resolvedVariables; } /** * Returns the IMember for the variable specified * * @param variable * @return */ public static IMember getMemberByVariable(ISeamContextVariable variable, boolean onlyEqualNames) { IMember member = null; if(variable instanceof ISeamContextShortVariable) { return getMemberByVariable(((ISeamContextShortVariable)variable).getOriginal(), onlyEqualNames); } if (variable instanceof ISeamComponent) { ISeamComponent component = (ISeamComponent)variable; ISeamJavaComponentDeclaration decl = component.getJavaDeclaration(); if (decl != null) { member = decl.getSourceMember(); } } if (member == null && variable instanceof IBijectedAttribute) { member = ((IJavaSourceReference)variable).getSourceMember(); } if (member == null && variable instanceof IJavaSourceReference) { member = ((IJavaSourceReference)variable).getSourceMember(); } if (member == null && variable instanceof ISeamXmlFactory) { ISeamXmlFactory factory = (ISeamXmlFactory)variable; String value = factory.getValue(); if (value != null && value.length() > 0) { if (value.startsWith("#{") || value.startsWith("${")) //$NON-NLS-1$ //$NON-NLS-2$ value = value.substring(2); if (value.endsWith("}")) //$NON-NLS-1$ value = value.substring(0, value.length() - 1); } if (value != null && value.length() > 0) { // TODO: Need to make sure that it's correct way to get the project and // the scope from the factory ISeamProject project = ((ISeamElement)factory).getSeamProject(); // ISeamProject project = getSeamProject(factory.getResource()); if (project != null) { List<ISeamContextVariable> resolvedValues = resolveVariables(project, null /* factory.getScope()*/, value, onlyEqualNames); for (ISeamContextVariable var : resolvedValues) { if (var.getName().equals(value)) { member = getMemberByVariable(var, onlyEqualNames); break; } } } } } return member; } /** * This object wraps "messages" context variable. * @author Alexey Kazakov */ public static class MessagesInfo extends TypeMemberInfo { private ISeamMessages messages; /** * @param parentMember * @param messages * @throws JavaModelException */ protected MessagesInfo(MemberInfo parentMember, ISeamMessages messages) throws JavaModelException { super(null, null, messages.getName(), 0, null, null, false, null); this.messages = messages; IMember member = (IMember)getJavaElement(); if(member!=null) { IType type = member.getDeclaringType(); if(member instanceof IType) { type = (IType)member; } if(type!=null) { setSourceType(type); setDeclaringTypeQualifiedName(type==null?null:type.getFullyQualifiedName()); setName(messages.getName()); setModifiers(type.getFlags()); setParentMember(parentMember); if(parentMember == null || parentMember instanceof TypeMemberInfo) { TypeInfo typeInfo = new TypeInfo(type, null, false); setDeclaratedType(typeInfo); } else { setDeclaratedType((TypeInfo)parentMember); } setDataModel(false); setType(type==null?null:new Type(null, type)); } } } /* * (non-Javadoc) * @see org.jboss.tools.common.model.util.TypeInfoCollector.MemberInfo#getJavaElement() */ @Override public IJavaElement getJavaElement() { if(messages instanceof IJavaSourceReference) { return ((IJavaSourceReference)messages).getSourceMember(); } else if(messages instanceof ISeamComponent) { ISeamComponent c = (ISeamComponent)messages; ISeamJavaComponentDeclaration d = c.getJavaDeclaration(); if(d != null) return d.getSourceMember(); } return null; } /** * @return property */ public ISeamMessages getMessages() { return messages; } /** * @return keys of resource bundle */ public Collection<String> getKeys() { return messages.getPropertyNames(); } /** * Returns mapping of property name to all model objects that represent it, * for all locales and all bundles. * * @return */ public Map<String, List<XModelObject>> getPropertiesMap() { return messages.getPropertiesMap(); } } /** * Returns the IMember for the variable specified * * @param variable * @return */ public static TypeInfoCollector.MemberInfo getMemberInfoByVariable(ISeamContextVariable variable, boolean onlyEqualNames, SeamELCompletionEngine engine, int offset) { TypeInfoCollector.MemberInfo member = null; if(variable instanceof ISeamContextShortVariable) { return getMemberInfoByVariable(((ISeamContextShortVariable)variable).getOriginal(), onlyEqualNames, engine, offset); } if(variable instanceof ISeamMessages) { MemberInfo info = null;; try { info = new MessagesInfo(null, (ISeamMessages)variable); } catch (JavaModelException e) { SeamCorePlugin.getPluginLog().logError(e); } return info; } if (variable instanceof ISeamComponent) { ISeamComponent component = (ISeamComponent)variable; // Use UNWRAP method type instead of ISeamComponent type if it exists IMember unwrapSourceMember = null; for (ISeamComponentMethod method : component.getMethods()) { if (method.getTypes()!= null && method.getTypes().contains(SeamComponentMethodType.UNWRAP) ) { unwrapSourceMember = method.getSourceMember(); break; } } if (unwrapSourceMember != null) { member = TypeInfoCollector.createMemberInfo(unwrapSourceMember); } else { ISeamJavaComponentDeclaration decl = component.getJavaDeclaration(); if (decl != null) { member = TypeInfoCollector.createMemberInfo(decl.getSourceMember()); } else { // Maybe it is framework component? Then let's try to find the class of it. String className = component.getClassName(); if(className!=null) { IJavaProject project = EclipseResourceUtil.getJavaProject(component.getSeamProject().getProject()); try { IType type = project.findType(className); if(type!=null) { member = TypeInfoCollector.createMemberInfo(type); } } catch (JavaModelException e) { SeamCorePlugin.getDefault().logError(e); } } } } } if (member == null && variable instanceof IBijectedAttribute) { boolean isDataModel = false; BijectedAttributeType[] types = ((IBijectedAttribute)variable).getTypes(); for(int i=0; i<types.length; i++) { if(types[i]==BijectedAttributeType.DATA_BINDER) { isDataModel = true; break; } } member = TypeInfoCollector.createMemberInfo(((IJavaSourceReference)variable).getSourceMember(), isDataModel); } if (member == null && variable instanceof IJavaSourceReference) { member = TypeInfoCollector.createMemberInfo(((IJavaSourceReference)variable).getSourceMember()); } if (member == null && variable instanceof ISeamXmlFactory) { ISeamXmlFactory factory = (ISeamXmlFactory)variable; String value = factory.getValue(); if (value != null && value.length() > 0) { if (value.startsWith("#{") || value.startsWith("${")) //$NON-NLS-1$ //$NON-NLS-2$ value = value.substring(2); if (value.endsWith("}")) //$NON-NLS-1$ value = value.substring(0, value.length() - 1); } if (value != null && value.length() > 0) { // TODO: Need to make sure that it's correct way to get the project and // the scope from the factory ISeamProject project = ((ISeamElement)factory).getSeamProject(); // ISeamProject project = getSeamProject(factory.getResource()); if (project != null) { List<ISeamContextVariable> resolvedValues = resolveVariables(project, null /* factory.getScope()*/, value, onlyEqualNames); for (ISeamContextVariable var : resolvedValues) { if (var.getName().equals(value)) { member = getMemberInfoByVariable(var, onlyEqualNames, engine, offset); break; } } } } if(member == null) { ELParser p = ELParserUtil.getJbossFactory().createParser(); ELModel m = p.parse(factory.getValue()); ELInstance i = m.getInstances().isEmpty() ? null : m.getInstances().get(0); ELExpression ex = i == null ? null : i.getExpression(); if(ex instanceof ELInvocationExpression) { ELInvocationExpression expr = (ELInvocationExpression)ex; try { ELResolution resolution = engine.resolveEL(null, null, expr, false, offset); if(resolution != null && resolution.isResolved()) { ELSegment segment = resolution.getLastSegment(); if(segment instanceof JavaMemberELSegmentImpl) { member = ((JavaMemberELSegmentImpl)segment).getMemberInfo(); } } } catch (StringIndexOutOfBoundsException e) { SeamCorePlugin.getDefault().logError(e); } catch (BadLocationException e) { SeamCorePlugin.getDefault().logError(e); } } } } return member; } }