/******************************************************************************* * 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.IProject; import org.eclipse.jdt.core.ElementChangedEvent; import org.eclipse.jdt.core.IElementChangedListener; import org.eclipse.jdt.core.IType; import org.eclipse.jdt.core.JavaCore; import org.eclipse.swt.widgets.Display; import org.jboss.tools.common.meta.XModelEntity; import org.jboss.tools.common.model.*; import org.jboss.tools.common.model.event.XModelTreeEvent; import org.jboss.tools.common.model.impl.RegularObjectImpl; import org.jboss.tools.common.model.util.EclipseResourceUtil; import org.jboss.tools.jsf.jsf2.bean.model.IJSF2ManagedBean; import org.jboss.tools.jsf.jsf2.bean.model.IJSF2Project; import org.jboss.tools.jsf.jsf2.bean.model.JSF2ProjectFactory; import org.jboss.tools.jsf.model.JSFConstants; import org.jboss.tools.jst.web.model.pv.WebProjectNode; public class JSFProjectBeans extends RegularObjectImpl implements WebProjectNode { private static final long serialVersionUID = 2682624545623269421L; private Map<String,IType> types = new HashMap<String,IType>(); protected boolean isLoading = false; protected boolean valid = false; public void invalidate() { if(!valid || isLoading) return; valid = false; fireStructureChanged(XModelTreeEvent.STRUCTURE_CHANGED, this); } public XModelObject[] getTreeChildren() { if(isLoading || valid) return getChildren(); isLoading = true; valid = true; try { updateListener(); XModelObject[] cs = getChildren(); Map<String,XModelObject> map = new HashMap<String,XModelObject>(); Map<String,JSFProjectBean> classes = new HashMap<String,JSFProjectBean>(); //include each class once for (int i = 0; i < cs.length; i++) map.put(cs[i].getPathPart(), cs[i]); List<XModelObject> list = JSFProjectConfiguration.getConfiguration(getModel()); XModelObject[] fcs = (XModelObject[])list.toArray(new XModelObject[0]); for (int i = 0; i < fcs.length; i++) { process(fcs[i], BeanConstants.MANAGED_BEAN_CONSTANTS, map, classes); process(fcs[i], BeanConstants.REFERENCED_BEAN_CONSTANTS, map, classes); } IJSF2Project jsf2 = JSF2ProjectFactory.getJSF2Project(EclipseResourceUtil.getProject(this), true); if(jsf2 != null) { for (IJSF2ManagedBean b: jsf2.getManagedBeans()) { process(b, map, classes); } } for(XModelObject o: map.values()) { o.removeFromParent(); } } finally { isLoading = false; } return getChildren(); } private void process(XModelObject fcg, BeanConstants constants, Map<String,XModelObject> map, Map<String,JSFProjectBean> classes) { XModelObject mb = fcg.getChildByPath(constants.folder); if(mb != null) process(mb.getChildren(), constants, map, classes); } private void process(XModelObject[] bs, BeanConstants constants, Map<String,XModelObject> map, Map<String,JSFProjectBean> classes) { for (int j = 0; j < bs.length; j++) { String bn = bs[j].getAttributeValue(constants.nameAttribute); String cn = bs[j].getAttributeValue(constants.classAttribute); if(!acceptClass(cn)) continue; if(classes.containsKey(cn)) { JSFProjectBean b = classes.get(cn); if(b != null) b.addBean(bs[j]); continue; } JSFProjectBean b = (JSFProjectBean)map.get(bn); IType type = getType(cn); if(b == null) { b = (JSFProjectBean)getModel().createModelObject(JSFProjectBean.ENTITY, null); b.setAttributeValue(XModelObjectConstants.ATTR_NAME, bn); b.setBeans(this); addChild(b); } else { map.remove(bn); b.cleanBeans(); } b.setAttributeValue(JSFProjectBean.ATTR_CLASS_NAME, cn); b.addBean(bs[j]); b.setType(type); classes.put(cn, b); } } private void process(IJSF2ManagedBean bean, Map<String,XModelObject> map, Map<String,JSFProjectBean> classes) { String bn = bean.getName(); String cn = bean.getBeanClass().getFullyQualifiedName(); if(!acceptClass(cn)) return; if(classes.containsKey(cn)) { return; } JSFProjectBean b = (JSFProjectBean)map.get(bn); IType type = bean.getBeanClass(); if(b == null) { b = (JSFProjectBean)getModel().createModelObject(JSFProjectBean.ENTITY, null); b.setAttributeValue(XModelObjectConstants.ATTR_NAME, bn); b.setBeans(this); addChild(b); } else { map.remove(bn); b.cleanBeans(); } b.setAttributeValue(JSFProjectBean.ATTR_CLASS_NAME, cn); b.setType(type); classes.put(cn, b); } static String primitive = "!int!char!boolean!short!double!long!void!byte!float!"; private boolean acceptClass(String classname) { if(classname == null) return false; if(classname.indexOf('.') < 0 && primitive.indexOf("!" + classname + "!") >= 0) return false; if(classname.indexOf('[') >= 0) { // We refuse to process arrays. Is this correct? return false; } return !classname.startsWith("java.") && !classname.startsWith("javax."); } public IType getType(String typename) { if(typename == null || typename.length() == 0 || !acceptClass(typename)) return null; IType type = (IType)types.get(typename); if(type != null && type.exists()) return type; if(type != null) types.remove(typename); IProject project = EclipseResourceUtil.getProject(this); if(project == null) return null; type = EclipseResourceUtil.getValidType(project, typename); if(type != null) types.put(typename, type); return type; } public XModelObject getTreeParent(XModelObject object) { if(isChild(object)) return this; return null; } public boolean isChild(XModelObject object) { return object != null && object.getParent() == this; } private void updateListener() { if(listener != null) return; if(EclipseResourceUtil.getProject(this) == null) return; listener = new JavaElementChangedListener(); JavaCore.addElementChangedListener(listener); } JavaElementChangedListener listener = null; private class JavaElementChangedListener implements IElementChangedListener { public void elementChanged(ElementChangedEvent event) { if(!isActive()) { JavaCore.removeElementChangedListener(this); } else { lazyInvalidate(); } } } private void lazyInvalidate() { if(!valid || isLoading) return; valid = false; Display.getDefault().asyncExec(new XJob.XRunnable() { public void run() { fireStructureChanged(XModelTreeEvent.STRUCTURE_CHANGED, this); } public String getId() { return "JSF Project Beans Update - " + XModelConstants.getWorkspace(getModel()); } }); } } class BeanConstants { static final BeanConstants MANAGED_BEAN_CONSTANTS = new BeanConstants(JSFConstants.FOLDER_MANAGED_BEANS, "managed-bean-name", "managed-bean-class"); static final BeanConstants REFERENCED_BEAN_CONSTANTS = new BeanConstants(JSFConstants.FOLDER_REFENCED_BEANS, "referenced-bean-name", "referenced-bean-class"); String folder; String nameAttribute; String classAttribute; BeanConstants(String folder, String nameAttribute, String classAttribute) { this.folder = folder; this.nameAttribute = nameAttribute; this.classAttribute = classAttribute; } public static BeanConstants getConstants(XModelObject bean) { if(bean == null) return null; XModelEntity entity = bean.getModelEntity(); if(entity.getAttribute(MANAGED_BEAN_CONSTANTS.nameAttribute) != null) return MANAGED_BEAN_CONSTANTS; if(entity.getAttribute(REFERENCED_BEAN_CONSTANTS.nameAttribute) != null) return REFERENCED_BEAN_CONSTANTS; return null; } }