/******************************************************************************* * 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.scanner.lib; import java.io.ByteArrayInputStream; import java.io.IOException; import org.eclipse.core.resources.IFile; import org.eclipse.core.runtime.IPath; import org.eclipse.core.runtime.Path; import org.eclipse.jdt.core.IClassFile; import org.eclipse.jdt.core.IJavaElement; import org.eclipse.jdt.core.IJavaProject; import org.eclipse.jdt.core.IPackageFragment; import org.eclipse.jdt.core.IPackageFragmentRoot; import org.eclipse.jdt.core.IParent; import org.eclipse.jdt.core.IType; import org.eclipse.jdt.core.JavaCore; import org.eclipse.jdt.core.JavaModelException; import org.eclipse.jdt.internal.compiler.classfmt.ClassFileReader; import org.eclipse.jdt.internal.compiler.classfmt.ClassFormatException; import org.eclipse.jdt.internal.compiler.env.IBinaryAnnotation; import org.jboss.tools.common.model.XModel; import org.jboss.tools.common.model.XModelObject; import org.jboss.tools.common.model.filesystems.impl.FileSystemsImpl; import org.jboss.tools.common.model.plugin.ModelPlugin; import org.jboss.tools.common.model.util.EclipseResourceUtil; import org.jboss.tools.common.model.util.XModelObjectUtil; import org.jboss.tools.jst.web.model.helpers.InnerModelHelper; import org.jboss.tools.seam.core.ISeamProject; import org.jboss.tools.seam.core.SeamCoreMessages; import org.jboss.tools.seam.internal.core.SeamNamespace; import org.jboss.tools.seam.internal.core.scanner.IFileScanner; import org.jboss.tools.seam.internal.core.scanner.LoadedDeclarations; import org.jboss.tools.seam.internal.core.scanner.ScannerException; import org.jboss.tools.seam.internal.core.scanner.java.SeamAnnotations; import org.jboss.tools.seam.internal.core.scanner.xml.PropertiesScanner; import org.jboss.tools.seam.internal.core.scanner.xml.XMLScanner; /** * @author Viacheslav Kabanovich */ public class LibraryScanner implements IFileScanner { ClassPath classPath = null; //Now it is absolute file on disk IPath sourcePath = null; public LibraryScanner() {} public void setClassPath(ClassPath classPath) { this.classPath = classPath; } public boolean isRelevant(IFile f) { if(EclipseResourceUtil.isJar(f.getName())) return true; return false; } XModelObject o = null; XModel model = null; public boolean isLikelyComponentSource(IFile f) { cleanState(); boolean isComponent = false; try { model = InnerModelHelper.createXModel(f.getProject()); if(model != null) { o = EclipseResourceUtil.getObjectByResource(model, f); if(o != null && o.getModelEntity().getName().equals("FileSystemJar")) { ((FileSystemsImpl)o.getModel().getByPath("FileSystems")).updateOverlapped(); //$NON-NLS-1$ o = EclipseResourceUtil.getObjectByResource(f); if(o != null && o.getModelEntity().getName().equals("FileSystemJar")) { isComponent = isLikelyComponentSource(o); } } } } finally { if(!isComponent) { cleanState(); } } return isComponent; } private void cleanState() { model = null; o = null; } public LoadedDeclarations parse(IFile f, ISeamProject sp) throws ScannerException { LoadedDeclarations decls = null; if(o!=null) { decls = parse(o, f.getFullPath(), sp); } return decls; } public static final boolean isLikelyComponentSource(XModelObject o) { return o.getChildByPath("seam.properties") != null || o.getChildByPath("META-INF/seam.properties") != null || o.getChildByPath("META-INF/components.xml") != null; } public LoadedDeclarations parse(XModelObject o, IPath path, ISeamProject sp) throws ScannerException { sourcePath = path; XModelObject seamProperties = o.getChildByPath("META-INF/seam.properties"); //$NON-NLS-1$ if(seamProperties == null) seamProperties = o.getChildByPath("seam.properties"); //$NON-NLS-1$ XModelObject componentsXML = o.getChildByPath("META-INF/components.xml"); //$NON-NLS-1$ if(componentsXML == null && seamProperties == null) return null; LoadedDeclarations ds = new LoadedDeclarations(); try { processJavaClasses(o, ds); } catch (JavaModelException e) { throw new ScannerException(SeamCoreMessages.LIBRARY_SCANNER_CANNOT_PROCESS_JAVA_CLASSES, e); } catch (ClassFormatException e) { throw new ScannerException(SeamCoreMessages.LIBRARY_SCANNER_CANNOT_PROCESS_JAVA_CLASSES, e); } catch (IOException e) { throw new ScannerException(SeamCoreMessages.LIBRARY_SCANNER_CANNOT_PROCESS_JAVA_CLASSES, e); } if(componentsXML != null) { LoadedDeclarations ds1 = new XMLScanner().parse(componentsXML, path, sp); if(ds1 != null) ds.add(ds1); } if(seamProperties != null) { PropertiesScanner scanner = new PropertiesScanner(); LoadedDeclarations ds1 = scanner.parse(seamProperties, path); if(ds1 != null) ds.add(ds1); } return ds; } protected void processJavaClasses(XModelObject o, LoadedDeclarations ds) throws JavaModelException, ClassFormatException, IOException { IJavaProject javaProject = JavaCore.create(classPath.getProject().getProject()); String location = o.getAttributeValue("location"); //$NON-NLS-1$ location = XModelObjectUtil.expand(location, o.getModel(), null); IFile[] fs = ModelPlugin.getWorkspace().getRoot().findFilesForLocation(new Path(location)); IPackageFragmentRoot root = null; if(fs != null) { for (int i = 0; i < fs.length && root == null; i++) { root = javaProject.findPackageFragmentRoot(fs[i].getFullPath()); } if(root == null) { root = javaProject.findPackageFragmentRoot(new Path(location)); } if(root != null) { process(root, ds); } } } protected void process(IParent element, LoadedDeclarations ds) throws JavaModelException, ClassFormatException, IOException { if(element == null) return; IJavaElement[] es = element.getChildren(); String prefix = null; for (int i = 0; i < es.length; i++) { if(es[i] instanceof IClassFile) { IClassFile typeRoot = (IClassFile)es[i]; if(es[i].getElementName().equals("package-info.class")) { prefix = processPackageInfo(typeRoot, ds); break; } } } for (int i = 0; i < es.length; i++) { if(es[i] instanceof IPackageFragment) { process((IPackageFragment)es[i], ds); } else if(es[i] instanceof IClassFile) { IClassFile typeRoot = (IClassFile)es[i]; if(es[i].getElementName().equals("package-info.class")) { continue; } else { processWithClassReader(typeRoot, ds, prefix); } } } } void processWithClassReader(IClassFile typeRoot, LoadedDeclarations ds, String prefix) throws JavaModelException, ClassFormatException, IOException { IType type = typeRoot.getType(); ClassFileReader reader = getReader(type, typeRoot); if(reader == null) return; LoadedDeclarations ds1 = null; //TODO use prefix TypeScanner scanner = new TypeScanner(); if(!scanner.isLikelyComponentSource(reader)) return; ds1 = scanner.parse(type, reader, sourcePath); if(ds1 != null) { ds.add(ds1); } } String processPackageInfo(IClassFile typeRoot, LoadedDeclarations ds) throws JavaModelException, ClassFormatException, IOException { IType type = typeRoot.getType(); ClassFileReader reader = getReader(type, typeRoot); if(reader == null) return null; IBinaryAnnotation[] as = reader.getAnnotations(); IBinaryAnnotation namespaceAnnotation = getNamespaceAnnotation(as); if(namespaceAnnotation == null) return null; String uri = TypeScanner.getValue(namespaceAnnotation, "value"); String prefix = TypeScanner.getValue(namespaceAnnotation, "prefix"); if(uri == null) return null; String className = type.getFullyQualifiedName(); int i = className.indexOf(".package-info"); if(i < 0) return null; String packageName = className.substring(0, i); SeamNamespace n = new SeamNamespace(); n.setSourcePath(sourcePath); n.setURI(uri); n.setPackage(packageName); ds.getNamespaces().add(n); return prefix; } static IBinaryAnnotation getNamespaceAnnotation(IBinaryAnnotation[] as) { if(as != null) { for (int i = 0; i < as.length; i++) { String type = TypeScanner.getTypeName(as[i]); if(type != null && type.equals(SeamAnnotations.NAMESPACE_ANNOTATION_TYPE)) { return as[i]; } } } return null; } private ClassFileReader getReader(IType type, IClassFile typeRoot) throws JavaModelException, ClassFormatException, IOException { String className = type.getFullyQualifiedName(); ClassFileReader newReader = null; byte[] bs = null; bs = typeRoot.getBytes(); return ClassFileReader.read(new ByteArrayInputStream(bs), className, false); } }