/******************************************************************************* * Copyright (c) 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 * * Contributors: * Red Hat, Inc. - initial API and implementation ******************************************************************************/ package org.jboss.tools.cdi.seam.config.core; import java.util.ArrayList; import java.util.List; import org.eclipse.core.resources.IFile; import org.eclipse.core.resources.IResource; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IPath; import org.eclipse.jdt.core.ICompilationUnit; import org.eclipse.jdt.core.IPackageFragmentRoot; import org.eclipse.jdt.core.IType; import org.eclipse.jface.text.Document; import org.eclipse.jface.text.IDocument; import org.eclipse.osgi.util.NLS; import org.jboss.tools.cdi.core.CDICoreNature; import org.jboss.tools.cdi.core.extension.ICDIExtension; import org.jboss.tools.cdi.core.extension.feature.IBuildParticipantFeature; import org.jboss.tools.cdi.core.extension.feature.IValidatorFeature; import org.jboss.tools.cdi.internal.core.impl.CDIProject; import org.jboss.tools.cdi.internal.core.impl.definition.TypeDefinition; import org.jboss.tools.cdi.internal.core.scanner.FileSet; import org.jboss.tools.cdi.internal.core.validation.CDICoreValidator; import org.jboss.tools.cdi.seam.config.core.definition.ConfigTypeDefinition; import org.jboss.tools.cdi.seam.config.core.definition.SAXNodeProblem; import org.jboss.tools.cdi.seam.config.core.definition.SeamBeanDefinition; import org.jboss.tools.cdi.seam.config.core.definition.SeamBeansDefinition; import org.jboss.tools.cdi.seam.config.core.definition.SeamFieldDefinition; import org.jboss.tools.cdi.seam.config.core.definition.SeamFieldValueDefinition; import org.jboss.tools.cdi.seam.config.core.definition.TextSourceReference; import org.jboss.tools.cdi.seam.config.core.scanner.ConfigFileSet; import org.jboss.tools.cdi.seam.config.core.scanner.SeamDefinitionBuilder; import org.jboss.tools.cdi.seam.config.core.validation.SeamConfigValidationMessages; import org.jboss.tools.cdi.seam.config.core.xml.SAXNode; import org.jboss.tools.common.EclipseUtil; import org.jboss.tools.common.java.IParametedType; import org.jboss.tools.common.java.ParametedType; import org.jboss.tools.common.model.XModelObject; import org.jboss.tools.common.model.filesystems.impl.FileAnyImpl; import org.jboss.tools.common.model.filesystems.impl.FolderImpl; import org.jboss.tools.common.model.util.EclipseResourceUtil; import org.jboss.tools.common.preferences.SeverityPreferences; import org.jboss.tools.common.text.ITextSourceReference; /** * * @author Viacheslav Kabanovich * */ public class CDISeamConfigExtension implements ICDIExtension, IBuildParticipantFeature, IValidatorFeature { private static String ID = "org.jboss.solder.config.xml.bootstrap.XmlConfigExtension"; private static String ID_30 = "org.jboss.seam.config.xml.bootstrap.XmlConfigExtension"; ConfigDefinitionContext context = new ConfigDefinitionContext(); ConfigFileSet fileSet = new ConfigFileSet(); public static CDISeamConfigExtension getExtension(CDICoreNature project) { ICDIExtension result = project.getExtensionManager().getExtensionByRuntime(ID); if(result == null) { result = project.getExtensionManager().getExtensionByRuntime(ID_30); } if(result instanceof CDISeamConfigExtension) { return (CDISeamConfigExtension)result; } return null; } public ConfigDefinitionContext getContext() { return context; } public void beginVisiting() { fileSet = new ConfigFileSet(); } public void visit(IFile file, IPath src, IPath webinf) { IPath path = file.getFullPath(); if(src != null && path.segmentCount() == src.segmentCount() + 2 && "META-INF".equals(path.segments()[path.segmentCount() - 2])) { addBeansXML(file, fileSet); } else if(webinf != null && webinf.isPrefixOf(path) && webinf.segmentCount() == path.segmentCount() - 1) { addBeansXML(file, fileSet); } else if(src != null && file.getName().endsWith(".java")) { //Check that Java type appeared that may resolve a node in seam beans xml. try { ICompilationUnit unit = EclipseUtil.getCompilationUnit(file); if(unit != null) { IType[] ts = unit.getTypes(); for (IType t: ts) { String type = t.getFullyQualifiedName(); IPath p = context.getWorkingCopy().getPathForPossibleType(type); if(p != null && fileSet.getBeanXML(p) == null) { IFile f = context.getRootContext().getProject().getProject().getWorkspace().getRoot().getFile(p); if(f.exists()) { addBeansXML(f, fileSet); } } } } } catch (CoreException e) { CDISeamConfigCorePlugin.getDefault().logError(e); } } } public void visitJar(IPath path, IPackageFragmentRoot root, XModelObject beansXML) { if(beansXML != null) { fileSet.setBeanXML(path, beansXML); XModelObject seamBeanXML = beansXML.getParent().getChildByPath(CDISeamConfigConstants.SEAM_BEANS_XML); if(seamBeanXML != null) { fileSet.setSeamBeanXML(path, seamBeanXML); } } } public void buildDefinitions() { List<SeamBeansDefinition> newDefinitions = new ArrayList<SeamBeansDefinition>(); for (IPath p: fileSet.getAllPaths()) { boolean isSeamBeans = false; XModelObject o = fileSet.getBeanXML(p); if(o == null) { o = fileSet.getSeamBeanXML(p); isSeamBeans = true; } if(o instanceof FileAnyImpl) { FileAnyImpl f = (FileAnyImpl)o; if(f.getParent() instanceof FolderImpl) { ((FolderImpl)f.getParent()).update(); } String text = f.getAsText(); IResource resource = (IResource)o.getAdapter(IResource.class); IDocument document = new Document(); SeamDefinitionBuilder builder = new SeamDefinitionBuilder(); document.set(text); SeamBeansDefinition def = builder.createDefinition(resource, document, context.getRootContext().getProject(), context.getWorkingCopy()); def.setFileObject(o); newDefinitions.add(def); if(isSeamBeans) { context.getWorkingCopy().addSeamBeanXML(p, def); } else { context.getWorkingCopy().addBeanXML(p, def); } } } for (SeamBeansDefinition def: newDefinitions) { //Or, should we just build through all context? def.buildTypeDefinitions(context.getWorkingCopy()); } //TODO } public void buildDefinitions(FileSet fileSet) { //nothing to do since we visited all resources. } public void buildBeans(CDIProject target) { //TODO } private void addBeansXML(IFile f, ConfigFileSet fileSet) { if(f.getName().equals("beans.xml")) { XModelObject beansXML = getObject(f); if(beansXML != null) { fileSet.setBeanXML(f.getFullPath(), beansXML); } } else if(f.getName().equals(CDISeamConfigConstants.SEAM_BEANS_XML)) { XModelObject beansXML = getObject(f); if(beansXML != null) { fileSet.setSeamBeanXML(f.getFullPath(), beansXML); } } } private XModelObject getObject(IFile f) { XModelObject o = EclipseResourceUtil.getObjectByResource(f); if(o == null) { o = EclipseResourceUtil.createObjectForResource(f); } return o; } public void validateResource(IFile file, CDICoreValidator validator) { SeamBeansDefinition def = context.getDefinition(file.getFullPath()); if(def != null) { for (SAXNodeProblem problem: def.getUnresolvedNodes()) { SAXNode node = problem.getNode(); String problemId = problem.getProblemId(); String message = problem.getMessage(); ITextSourceReference ref = new TextSourceReference(def.getFileObject(), file, node); if(CDISeamConfigConstants.ERROR_UNRESOLVED_TYPE.equals(problemId)) { validator.addError(message, CDISeamConfigPreferences.UNRESOLVED_TYPE, ref, file); } else if(CDISeamConfigConstants.ERROR_UNRESOLVED_MEMBER.equals(problemId)) { validator.addError(message, CDISeamConfigPreferences.UNRESOLVED_MEMBER, ref, file); } else if(CDISeamConfigConstants.ERROR_UNRESOLVED_METHOD.equals(problemId)) { validator.addError(message, CDISeamConfigPreferences.UNRESOLVED_METHOD, ref, file); } else if(CDISeamConfigConstants.ERROR_UNRESOLVED_CONSTRUCTOR.equals(problemId)) { validator.addError(message, CDISeamConfigPreferences.UNRESOLVED_CONSTRUCTOR, ref, file); } else if(CDISeamConfigConstants.ERROR_ANNOTATION_EXPECTED.equals(problemId)) { validator.addError(message, CDISeamConfigPreferences.ANNOTATION_EXPECTED, ref, file); } } for (SeamBeanDefinition b: def.getBeanDefinitions()) { List<SeamFieldDefinition> fs = b.getFields(); for (SeamFieldDefinition f: fs) { List<SeamFieldValueDefinition> vs = f.getValueDefinitions(); if(vs.isEmpty()) continue; for (SeamFieldValueDefinition v: vs) { IParametedType requiredType = v.getRequiredType(); SeamBeanDefinition inline = v.getInlineBean(); ConfigTypeDefinition d = inline.getConfigType(); IParametedType actualType = d.getParametedType(); if(requiredType != null && actualType != null) { if(!((ParametedType)actualType).isAssignableTo((ParametedType)requiredType, true)) { String actual = actualType.getSimpleName(); String required = requiredType.getSimpleName(); String message = NLS.bind(SeamConfigValidationMessages.INLINE_BEAN_TYPE_MISMATCH, actual, required); validator.addError(message, CDISeamConfigPreferences.INLINE_BEAN_TYPE_MISMATCH, new TextSourceReference(def.getFileObject(), file, inline.getNode()), file); } } } } } List<TypeDefinition> ds = def.getTypeDefinitions(); for (TypeDefinition d: ds) { if(!d.hasBeanConstructor()) { ConfigTypeDefinition cd = (ConfigTypeDefinition)d; SAXNode n = cd.getConfig().getNode(); if(d.isAbstract()) { String message = NLS.bind(SeamConfigValidationMessages.TYPE_IS_ABSTRACT, cd.getParametedType().getSimpleName()); validator.addError(message, CDISeamConfigPreferences.ABSTRACT_TYPE_IS_CONFIGURED_AS_BEAN, new TextSourceReference(def.getFileObject(), file, n), file); } else { String message = NLS.bind(SeamConfigValidationMessages.NO_BEAN_CONSTRUCTOR, cd.getParametedType().getSimpleName()); validator.addError(message, CDISeamConfigPreferences.BEAN_CONSTRUCTOR_IS_MISSING, new TextSourceReference(def.getFileObject(), file, n), file); } } } } } public SeverityPreferences getSeverityPreferences() { return CDISeamConfigPreferences.getInstance(); } }