/******************************************************************************* * Copyright (c) 2007 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: * Red Hat, Inc. - initial API and implementation ******************************************************************************/ package org.jboss.tools.seam.internal.core; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Properties; import java.util.Set; import org.eclipse.core.resources.IResource; import org.eclipse.core.runtime.CoreException; import org.eclipse.jdt.core.IJavaElement; import org.eclipse.jdt.core.IMember; import org.eclipse.jdt.core.IType; import org.eclipse.jdt.core.JavaModelException; import org.eclipse.jdt.ui.JavaUI; import org.jboss.tools.common.java.IJavaSourceReference; import org.jboss.tools.common.meta.action.impl.SpecialWizardSupport; import org.jboss.tools.common.model.ServiceDialog; import org.jboss.tools.common.model.options.PreferenceModelUtilities; import org.jboss.tools.common.model.project.ext.IValueInfo; import org.jboss.tools.common.model.project.ext.event.Change; import org.jboss.tools.common.model.util.EclipseJavaUtil; import org.jboss.tools.common.text.ITextSourceReference; import org.jboss.tools.common.xml.XMLUtilities; import org.jboss.tools.jst.web.model.project.ext.store.XMLStoreHelper; import org.jboss.tools.seam.core.BeanType; import org.jboss.tools.seam.core.BijectedAttributeType; import org.jboss.tools.seam.core.IBijectedAttribute; import org.jboss.tools.seam.core.IRole; 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.ISeamProject; import org.jboss.tools.seam.core.ISeamXmlComponentDeclaration; import org.jboss.tools.seam.core.ScopeType; import org.jboss.tools.seam.core.SeamComponentMethodType; import org.jboss.tools.seam.core.SeamComponentPrecedenceType; import org.jboss.tools.seam.core.SeamCorePlugin; import org.w3c.dom.Element; public class SeamJavaComponentDeclaration extends SeamComponentDeclaration implements ISeamJavaComponentDeclaration { public static final String PATH_OF_STATEFUL = "stateful"; //$NON-NLS-1$ protected String className = null; protected ScopeType scopeType = ScopeType.UNSPECIFIED; Map<BeanType, IValueInfo> types = null; protected int precedence = SeamComponentPrecedenceType.DEFAULT; protected IType type; protected Set<IBijectedAttribute> bijectedAttributes = new HashSet<IBijectedAttribute>(); protected Set<ISeamComponentMethod> componentMethods = new HashSet<ISeamComponentMethod>(); protected Set<IRole> roles = new HashSet<IRole>(); protected Set<String> imports = new HashSet<String>(); public Set<ISeamContextVariable> getVariablesByName(String name) { Set<ISeamContextVariable> result = new HashSet<ISeamContextVariable>(); for (String s: imports) { lookUpForVariable(s, name, result); } if(result.isEmpty()) { List<SeamImport> is = ((SeamProject)getSeamProject()).getPackageImports(this); if(is != null && !is.isEmpty()) { for (SeamImport i: is) { lookUpForVariable(i.getSeamPackage(), name, result); } } } return result; } @Override public ITextSourceReference getLocationFor(String path) { final IValueInfo valueInfo = attributes.get(path); IJavaSourceReference reference = new IJavaSourceReference() { public int getLength() { return valueInfo != null ? valueInfo.getLength() : 0; } public int getStartPosition() { return valueInfo != null ? valueInfo.getStartPosition() : 0; } public IResource getResource() { return resource; } public IMember getSourceMember() { return type; } public IJavaElement getSourceElement() { return SeamJavaComponentDeclaration.this.getSourceElement(); } }; return reference; } private void lookUpForVariable(String importname, String name, Set<ISeamContextVariable> result) { String qname = importname + "." + name; Set<ISeamContextVariable> c = getSeamProject().getVariablesByName(qname); if((c == null || c.isEmpty()) && getSeamProject().getParentProject() != null) c = getSeamProject().getParentProject().getVariablesByName(qname); if(c != null && !c.isEmpty()) { result.addAll(c); for (ISeamContextVariable v: c) { if(v instanceof ISeamContextShortVariable) continue; result.add(new SeamContextShortVariable(v, importname + ".")); } } } public void setType(IType type) { this.type = type; } public ScopeType getScope() { if(scopeType != null && scopeType != ScopeType.UNSPECIFIED) { return scopeType; } if(isEntity() || isStateful()) { return ScopeType.CONVERSATION; } if(isOfType(BeanType.STATELESS) || isOfType(BeanType.MESSAGE_DRIVEN)) { return ScopeType.STATELESS; } return ScopeType.EVENT; } public void setScope(String scope) { if(scope == null || scope.length() == 0) { scopeType = ScopeType.UNSPECIFIED; } else { try { scopeType = ScopeType.valueOf(scope.toUpperCase()); } catch (IllegalArgumentException e) { scopeType = ScopeType.UNSPECIFIED; } } } public String getClassName() { return className; } public void setClassName(String className) { this.className = className; } public void addBijectedAttribute(IBijectedAttribute attribute) { bijectedAttributes.add(attribute); adopt(attribute); } public void addMethod(ISeamComponentMethod method) { componentMethods.add(method); adopt(method); } public void addRole(IRole role) { roles.add(role); adopt(role); } public void addImport(String value) { imports.add(value); } public Set<IBijectedAttribute> getBijectedAttributes() { return bijectedAttributes; } public Set<IBijectedAttribute> getBijectedAttributesByName(String name) { Set<IBijectedAttribute> result = null; for(IBijectedAttribute a: getBijectedAttributes()) { if(name.equals(a.getName())) { if(result == null) result = new HashSet<IBijectedAttribute>(); result.add(a); } } return result; } public Set<IBijectedAttribute> getBijectedAttributesByType( BijectedAttributeType type) { Set<IBijectedAttribute> result = null; for(IBijectedAttribute a: getBijectedAttributes()) { if(a.isOfType(type)) { if(result == null) result = new HashSet<IBijectedAttribute>(); result.add(a); } } return result; } public Set<ISeamComponentMethod> getMethods() { return componentMethods; } public Set<ISeamComponentMethod> getMethodsByType( SeamComponentMethodType type) { Set<ISeamComponentMethod> result = null; Set<String> names = null; for(ISeamComponentMethod a: getMethods()) { if(a.isOfType(type)) { if(result == null) { result = new HashSet<ISeamComponentMethod>(); names = new HashSet<String>(); } result.add(a); if(a.getSourceMember() != null) { names.add(a.getSourceMember().getElementName()); } } } ISeamJavaComponentDeclaration superDeclaration = getSuperDeclaration(); if(superDeclaration != null) { Set<ISeamComponentMethod> s = superDeclaration.getMethodsByType(type); if(s != null) for(ISeamComponentMethod a: s) { if(a.getSourceMember() == null) continue; String n = a.getSourceMember().getElementName(); if(names != null && names.contains(n)) continue; if(result == null) { result = new HashSet<ISeamComponentMethod>(); names = new HashSet<String>(); } result.add(a); if(a.getSourceMember() != null) { names.add(a.getSourceMember().getElementName()); } } } return result; } public ISeamJavaComponentDeclaration getSuperDeclaration() { if(type == null) return null; String superclass = null; try { superclass = type.getSuperclassName(); } catch (JavaModelException e) { return null; } if(superclass == null || "java.lang.Object".equals(superclass)) { return null; } if(superclass.indexOf('.') < 0) { superclass = EclipseJavaUtil.resolveType(type, superclass); } if(superclass != null && superclass.equals(type.getFullyQualifiedName())) { //FIX JBIDE-1642 return null; } SeamProject p = (SeamProject)getSeamProject(); return p == null ? null : p.getJavaComponentDeclaration(superclass); } public Set<IRole> getRoles() { return roles; } public Set<String> getImports() { return imports; } public boolean isOfType(BeanType type) { return types != null && types.containsKey(type); } public boolean isEntity() { return isOfType(BeanType.ENTITY); } public boolean isStateful() { return isOfType(BeanType.STATEFUL); } public boolean isStateless() { return isOfType(BeanType.STATELESS); } public void removeBijectedAttribute(IBijectedAttribute attribute) { bijectedAttributes.remove(attribute); } public void removeMethod(ISeamComponentMethod method) { componentMethods.remove(method); } public void removeRole(IRole role) { roles.remove(role); } public void removeImport(String value) { imports.remove(value); } public IMember getSourceMember() { return type; } /** * Merges loaded data into currently used declaration. * If changes were done returns a list of changes. * @param d * @return list of changes */ @Override public List<Change> merge(ISeamElement s) { List<Change> changes = super.merge(s); SeamJavaComponentDeclaration jd = (SeamJavaComponentDeclaration)s; if(!stringsEqual(className, jd.className)) { changes = Change.addChange(changes, new Change(this, "class", className, jd.className)); //$NON-NLS-1$ className = jd.className; } if(scopeType != jd.scopeType) { changes = Change.addChange(changes, new Change(this, "scope", scopeType, jd.scopeType)); //$NON-NLS-1$ scopeType = jd.scopeType; } if(precedence != jd.precedence) { changes = Change.addChange(changes, new Change(this, "precedence", precedence, jd.precedence)); //$NON-NLS-1$ precedence = jd.precedence; } if(type != jd.type) type = jd.type; if(!typesAreEqual(types, jd.types)) { changes = Change.addChange(changes, new Change(this, "types", types, jd.types)); //$NON-NLS-1$ } this.types = jd.types; Change children = new Change(this, null, null, null); mergeComponentMethods(jd, children); mergeBijected(jd, children); mergeRoles(jd, children); mergeImports(jd, children); changes = Change.addChange(changes, children); return changes; } public void mergeBijected(SeamJavaComponentDeclaration jd, Change children) { Map<Object, BijectedAttribute> bijectedMap = new HashMap<Object, BijectedAttribute>(); for (IBijectedAttribute r: bijectedAttributes) bijectedMap.put(((SeamObject)r).getId(), (BijectedAttribute)r); for (IBijectedAttribute r: jd.bijectedAttributes) { BijectedAttribute loaded = (BijectedAttribute)r; BijectedAttribute current = (BijectedAttribute)bijectedMap.remove(loaded.getId()); if(current == null) { adopt(loaded); bijectedAttributes.add(loaded); ISeamProject p = getSeamProject(); if(p != null && loaded.isContextVariable()) { p.addVariable(loaded); } Change change = new Change(this, null, null, loaded); children.addChildren(Change.addChange(null, change)); } else { boolean wasOut = current.isContextVariable(); boolean isOut = loaded.isContextVariable(); List<Change> rc = current.merge(loaded); if(rc != null) children.addChildren(rc); if(wasOut != isOut) { ISeamProject p = getSeamProject(); if(p != null) { if(wasOut) p.removeVariable(current); if(isOut) p.addVariable(current); } } } } for (BijectedAttribute r: bijectedMap.values()) { bijectedAttributes.remove(r); ISeamProject p = getSeamProject(); if(p != null) p.removeVariable(r); Change change = new Change(this, null, r, null); children.addChildren(Change.addChange(null, change)); } } public void mergeRoles(SeamJavaComponentDeclaration jd, Change children) { Map<Object, Role> roleMap = new HashMap<Object, Role>(); for (IRole r: roles) roleMap.put(((SeamObject)r).getId(), (Role)r); for (IRole r: jd.roles) { Role loaded = (Role)r; Role current = (Role)roleMap.remove(loaded.getId()); if(current == null) { adopt(loaded); roles.add(loaded); ISeamProject p = getSeamProject(); if(p != null) p.addVariable(loaded); Change change = new Change(this, null, null, loaded); children.addChildren(Change.addChange(null, change)); } else { List<Change> rc = current.merge(loaded); if(rc != null) children.addChildren(rc); } } for (Role r: roleMap.values()) { roles.remove(r); ISeamProject p = getSeamProject(); if(p != null) p.removeVariable(r); Change change = new Change(this, null, r, null); children.addChildren(Change.addChange(null, change)); } } public void mergeImports(SeamJavaComponentDeclaration jd, Change children) { Map<Object, String> importMap = new HashMap<Object, String>(); for (String r: imports) importMap.put(r, r); for (String r: jd.imports) { String loaded = r; String current = importMap.remove(loaded); if(current == null) { imports.add(loaded); Change change = new Change(this, null, null, loaded); children.addChildren(Change.addChange(null, change)); } else { //nothing to merge as long as import is a String } } for (String r: importMap.values()) { imports.remove(r); Change change = new Change(this, null, r, null); children.addChildren(Change.addChange(null, change)); } } public void mergeComponentMethods(SeamJavaComponentDeclaration jd, Change children) { Map<Object, SeamComponentMethod> methodsMap = new HashMap<Object, SeamComponentMethod>(); for (ISeamComponentMethod r: componentMethods) methodsMap.put(((SeamObject)r).getId(), (SeamComponentMethod)r); for (ISeamComponentMethod r: jd.componentMethods) { SeamComponentMethod loaded = (SeamComponentMethod)r; SeamComponentMethod current = (SeamComponentMethod)methodsMap.remove(loaded.getId()); if(current == null) { adopt(loaded); componentMethods.add(loaded); Change change = new Change(this, null, null, loaded); children.addChildren(Change.addChange(null, change)); } else { List<Change> rc = current.merge(loaded); if(rc != null) children.addChildren(rc); } } for (SeamComponentMethod r: methodsMap.values()) { componentMethods.remove(r); Change change = new Change(this, null, r, null); children.addChildren(Change.addChange(null, change)); } } boolean typesAreEqual(Map<BeanType, IValueInfo> types1, Map<BeanType, IValueInfo> types2) { if(types1 == null || types2 == null) return types2 == types1; if(types1.size() != types2.size()) return false; for (BeanType t : types1.keySet()) { if(!types2.containsKey(t)) return false; } return true; } /** * @see org.jboss.tools.seam.core.ISeamJavaComponentDeclaration#getPrecedence() */ public int getPrecedence() { return precedence; } /** * @see org.jboss.tools.seam.core.ISeamJavaComponentDeclaration#setPrecedence(org.jboss.tools.seam.core.SeamComponentPrecedenceType) */ public void setPrecedence(int precedence) { this.precedence = precedence; } public void setScope(IValueInfo value) { attributes.put(ISeamXmlComponentDeclaration.SCOPE, value); setScope(value == null ? null : value.getValue()); } static final Map<String, Integer> NAMED_PRECEDENCES = new HashMap<String, Integer>(); static { NAMED_PRECEDENCES.put("Install.BUILT_IN", Integer.valueOf(0)); //$NON-NLS-1$ NAMED_PRECEDENCES.put("Install.FRAMEWORK", Integer.valueOf(10)); //$NON-NLS-1$ NAMED_PRECEDENCES.put("Install.APPLICATION", Integer.valueOf(20)); //$NON-NLS-1$ NAMED_PRECEDENCES.put("Install.DEPLOYMENT", Integer.valueOf(30)); //$NON-NLS-1$ NAMED_PRECEDENCES.put("Install.MOCK", Integer.valueOf(40)); //$NON-NLS-1$ } public void setPrecedence(IValueInfo value) { attributes.put(ISeamXmlComponentDeclaration.PRECEDENCE, value); String p = value == null ? null : value.getValue(); if(p == null) { setPrecedence(0); return; } Integer i = NAMED_PRECEDENCES.get(p); if(i == null) try { i = Integer.parseInt(p); } catch (NumberFormatException e) { //ignore - exact value is stored in ValueInfo } setPrecedence(i == null ? -1 : i.intValue()); } public void setTypes(Map<BeanType, IValueInfo> types) { this.types = types; } public Set<ISeamContextVariable> getDeclaredVariables() { Set<ISeamContextVariable> set = new HashSet<ISeamContextVariable>(); set.addAll(roles); for (IBijectedAttribute a : bijectedAttributes) { if(a.isContextVariable()) set.add(a); } return set; } public void open() { if(type == null) return; if(!type.exists()) { ServiceDialog d = PreferenceModelUtilities.getPreferenceModel().getService(); d.showDialog("Warning", "Type " + type.getElementName() + " does not exist.", new String[]{SpecialWizardSupport.OK}, null, ServiceDialog.WARNING); return; } try { JavaUI.openInEditor(type); } catch (CoreException e) { SeamCorePlugin.getPluginLog().logError(e); } } public SeamJavaComponentDeclaration clone() throws CloneNotSupportedException { SeamJavaComponentDeclaration c = (SeamJavaComponentDeclaration)super.clone(); if(types != null) { c.types = new HashMap<BeanType, IValueInfo>(); c.types.putAll(types); } c.bijectedAttributes = new HashSet<IBijectedAttribute>(); for (IBijectedAttribute a : bijectedAttributes) { c.addBijectedAttribute(a.clone()); } c.componentMethods = new HashSet<ISeamComponentMethod>(); for (ISeamComponentMethod m : componentMethods) { c.addMethod(m.clone()); } c.roles = new HashSet<IRole>(); for (IRole r : roles) { c.addRole(r.clone()); } c.imports = new HashSet<String>(); c.imports.addAll(imports); return c; } public String getXMLClass() { return SeamXMLConstants.CLS_JAVA; } static String ATTR_CLASS_NAME = "class-name"; public Element toXML(Element parent, Properties context) { Element element = super.toXML(parent, context); if(scopeType != null) { element.setAttribute(SeamXMLConstants.ATTR_SCOPE, scopeType.toString()); } if(types != null) { Element e_types = XMLUtilities.createElement(element, "bean-types"); for (BeanType t: types.keySet()) { IValueInfo v = types.get(t); if(v == null) continue; Element e_type = XMLUtilities.createElement(e_types, "bean-type"); e_type.setAttribute(SeamXMLConstants.ATTR_NAME, t.toString()); XMLStoreHelper.saveValueInfo(e_type, v, context); } } element.setAttribute(SeamXmlComponentDeclaration.PRECEDENCE, "" + precedence); if(type != null && type != id) { XMLStoreHelper.saveType(element, type, "type", context); } if(type != null) context.put(SeamXMLConstants.ATTR_TYPE, type); if(className != null && (type == null || !className.equals(type.getFullyQualifiedName()))) { element.setAttribute(ATTR_CLASS_NAME, className); } if(!bijectedAttributes.isEmpty()) { Element b = XMLUtilities.createElement(element, "bijected"); for (IBijectedAttribute a: bijectedAttributes) { SeamObject o = (SeamObject)a; o.toXML(b, context); } } if(!componentMethods.isEmpty()) { Element b = XMLUtilities.createElement(element, "methods"); for (ISeamComponentMethod a: componentMethods) { SeamObject o = (SeamObject)a; o.toXML(b, context); } } if(!roles.isEmpty()) { Element b = XMLUtilities.createElement(element, "roles"); for (IRole a: roles) { SeamObject o = (SeamObject)a; o.toXML(b, context); } } if(!imports.isEmpty()) { Element b = XMLUtilities.createElement(element, "imports"); for (String s: imports) { Element i = XMLUtilities.createElement(b, "import"); i.setAttribute(SeamXMLConstants.ATTR_VALUE, s); } } context.remove(SeamXMLConstants.ATTR_TYPE); return element; } public void loadXML(Element element, Properties context) { super.loadXML(element, context); setScope(element.getAttribute(SeamXMLConstants.ATTR_SCOPE)); Element e_imports = XMLUtilities.getUniqueChild(element, "imports"); if(e_imports != null) { Element[] cs = XMLUtilities.getChildren(e_imports, "import"); for (Element c: cs) { String v = c.getAttribute(SeamXMLConstants.ATTR_VALUE); if(v != null && v.length() > 0) imports.add(v); } } Element e_types = XMLUtilities.getUniqueChild(element, "bean-types"); if(e_types != null) { types = new HashMap<BeanType, IValueInfo>(); Element[] e_type = XMLUtilities.getChildren(e_types, "bean-type"); for (int i = 0; i < e_type.length; i++) { String name = e_type[i].getAttribute(SeamXMLConstants.ATTR_NAME); BeanType t = null; try { t = BeanType.valueOf(name); } catch (IllegalArgumentException e) { continue; } if(t == null) continue; IValueInfo value = XMLStoreHelper.loadValueInfo(e_type[i], context); if(value != null) { types.put(t, value); } } } if(element.hasAttribute(SeamXmlComponentDeclaration.PRECEDENCE)) { String v = element.getAttribute(SeamXmlComponentDeclaration.PRECEDENCE); if(v != null && v.length() > 0) { try { precedence = Integer.parseInt(v); } catch (NumberFormatException e) { //ignore } } } Element e_type = XMLUtilities.getUniqueChild(element, "type"); if(e_type != null) { type = XMLStoreHelper.loadType(e_type, context); } else if(id instanceof IType) { type = (IType)id; } if(type != null) context.put(SeamXMLConstants.ATTR_TYPE, type); if(element.hasAttribute(ATTR_CLASS_NAME)) { className = element.getAttribute(ATTR_CLASS_NAME); } else if(type != null) { className = type.getFullyQualifiedName(); } Element b = XMLUtilities.getUniqueChild(element, "bijected"); if(b != null) { Element[] cs = XMLUtilities.getChildren(b, SeamXMLConstants.TAG_BIJECTED_ATTRIBUTE); for (int i = 0; i < cs.length; i++) { String cls = cs[i].getAttribute(SeamXMLConstants.ATTR_CLASS); BijectedAttribute a = null; if(SeamXMLConstants.CLS_DATA_MODEL.equals(cls)) { a = new DataModelSelectionAttribute(); } else { a = new BijectedAttribute(); } a.loadXML(cs[i], context); addBijectedAttribute(a); } } b = XMLUtilities.getUniqueChild(element, "methods"); if(b != null) { Element[] cs = XMLUtilities.getChildren(b, SeamXMLConstants.TAG_METHOD); for (int i = 0; i < cs.length; i++) { SeamComponentMethod a = new SeamComponentMethod(); a.loadXML(cs[i], context); addMethod(a); } } b = XMLUtilities.getUniqueChild(element, "roles"); if(b != null) { Element[] cs = XMLUtilities.getChildren(b, SeamXMLConstants.TAG_ROLE); for (int i = 0; i < cs.length; i++) { Role a = new Role(); a.loadXML(cs[i], context); addRole(a); } } context.remove(SeamXMLConstants.ATTR_TYPE); } @Override public IJavaElement getSourceElement() { return getSourceMember(); } }