/******************************************************************************* * Copyright © 2000, 2013 IBM Corporation and others. * All rights reserved. This program and the accompanying materials * are 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: * IBM Corporation - initial API and implementation * *******************************************************************************/ package org.eclipse.edt.ide.core.internal.search; import java.io.File; import java.util.ArrayList; import java.util.Arrays; import java.util.Comparator; import java.util.Iterator; import java.util.List; import org.eclipse.core.resources.ResourcesPlugin; import org.eclipse.core.runtime.IPath; import org.eclipse.edt.compiler.internal.eglar.FileInEglar; import org.eclipse.edt.ide.core.model.EGLCore; import org.eclipse.edt.ide.core.model.EGLModelException; import org.eclipse.edt.ide.core.model.IEGLModel; import org.eclipse.edt.ide.core.model.IEGLProject; import com.ibm.icu.util.StringTokenizer; public class PartInfoFactory { private String[] fProjects; private PartInfo fLast; private char[] fBuffer; private static final String EGL= "egl"; //$NON-NLS-1$ public PartInfoFactory() { super(); fProjects= getProjectList(); fLast= null; fBuffer= new char[512]; } //path: the path where the eglar/ir file is located. For external eglar, it is the external file system location; for //non-external eglar, it is the location that contains the eglar //projectPath: the project that imports the eglar public PartInfo create(char[] packageName, char[] typeName, char[][] enclosingName, char partType, String path, IPath projectPath) { String pn= getPackageName(packageName); String tn= new String(typeName); PartInfo result= null; String eglarDefProject= getProject(path); //the project in which the eglar is contained (not necessarily the project importing eglar) if (eglarDefProject != null) { result= createPartDeclarationInfo(pn, tn, enclosingName, partType, path, getIFilePartInfo(fLast), projectPath.toString()); } else if(eglarDefProject == null){ //for external eglar file result = createExternalPartDeclarationInfo(pn, tn, enclosingName, partType, path, getIFilePartInfo(fLast), projectPath.toString()); } if (result == null) { result= new UnresolvablePartInfo(pn, tn, enclosingName, path); } else { fLast= result; } return result; } private static IFilePartInfo getIFilePartInfo(PartInfo info) { if (info == null || info.getElementType() != PartInfo.IFILE_TYPE_INFO) return null; return (IFilePartInfo)info; } //example of path: //1. /Test1/Test.eglar|rec_without_package.eglxml //2. /Test1/Test.eglar|int1/rec1.eglxml //3. /Test1/EGLSource/pgm1.egl //4. /Test1/EGLSource/mypkg/pkg1/pgm1.egl //example of projecT: //1. /Test1 private PartInfo createPartDeclarationInfo(String packageName, String typeName, char[][] enclosingName, char partType, String path, IFilePartInfo last, String project) { String src = null; String file= null; String extension= null; String container = null; int index = -1; if(path.startsWith("/")){ index = path.indexOf("/"); if(index == -1){ return null; } } index = path.indexOf("/", index + 1); if(index == -1){ return null; } container = path.substring(0, index); if(container.startsWith("/")){ container = container.substring(1); } String rest = path.substring(index); // the first slashes. //example of rest: //1. /Test.eglar|rec_without_package.eglxml //2. /Test.eglar|int1/rec1.eglxml //3. /EGLSource/pgm1.egl //4. /EGLSource/mypkg/pkg1/pgm1.egl index = rest.indexOf(FileInEglar.EGLAR_SEPARATOR); if(index == -1){ //for source part index = rest.lastIndexOf(PartInfo.SEPARATOR); if (index == -1) return null; //middle: the path without project part and file part String middle= rest.substring(0, index + 1); //middle includes the last '/' rest = rest.substring(index + 1); index= rest.lastIndexOf(PartInfo.EXTENSION_SEPARATOR); if (index != -1) { file= rest.substring(0, index); extension= rest.substring(index + 1); } else { return null; } // If the package name does not match the directory structure, there is no way to determine what part of the path is // the source directory and what part is the package name. So, treat the entire path as the source directory and the // package as default if (!packageMatchesDirectoryStructure(middle, packageName)) { packageName = ""; src = middle.substring(1, middle.length()); } else { int ml= middle.length() - 1; //eliminates the length of last '/' int pl= packageName.length(); // if we have a source or package then we have to substract the leading '/' if (ml > 0 && ml - 1 > pl) { // If we have a package then we have to substract the '/' between src and package src= middle.substring(1, ml - pl - (pl > 0 ? 1 : 0)); } } if (last != null) { if (src != null && src.equals(last.getFolder())) src= last.getFolder(); } if (typeName.equals(file)) { file= typeName; } else { file= createString(file); } if (EGL.equals(extension)) extension= EGL; else extension= createString(extension); } else{ //for binary part src = rest.substring(1, index); //e.g. Test.eglar rest = rest.substring(index + 1); if(packageName != null && packageName.length() > 0){ //not in default package int ind = rest.lastIndexOf(PartInfo.SEPARATOR); if(ind == -1){ return null; } rest = rest.substring(ind + 1); //substract the package name } index = rest.lastIndexOf(PartInfo.EXTENSION_SEPARATOR); if(index == -1) return null; file= rest.substring(0, index); extension= rest.substring(index + 1); } if(project.startsWith(File.separator) || project.startsWith("/")){ project = project.substring(1); } return new PartDeclarationInfo(packageName, typeName, enclosingName, project, container, src, file, extension, partType, false); } //example of path: //1. /Test.eglar|inter1 //2. /Test.eglar|mypkg/inter1/ //3. /EGLSource/dojo/widgets/ //example of pkgName: //1. (empty string) //2. mypkg.inter1 private boolean packageMatchesDirectoryStructure(String path, String pkgName) { if (pkgName == null || pkgName.length() == 0) { return true; } //parse through the package name and store the package name elements in a list is reverse order List list = new ArrayList(); StringTokenizer tokenizer = new StringTokenizer(pkgName, ".", false); while (tokenizer.hasMoreTokens()) { String pkgElem = tokenizer.nextToken() + PartInfo.SEPARATOR; list.add(0, pkgElem); } //Check the package name elements against the directory structure Iterator i = list.iterator(); while (i.hasNext()) { String pkgElem = (String) i.next(); if (path.endsWith(pkgElem)) { path = path.substring(0, path.length() - pkgElem.length()); } else { return false; } } return true; } //example of path: //1. c:\temp\Test.eglar|rec_without_package.eglxml //2. c:\temp\Test.eglar|int1/rec1.eglxml private PartInfo createExternalPartDeclarationInfo(String packageName, String typeName, char[][] enclosingName, char partType, String path, IFilePartInfo last, String project) { String rest = path; if ( rest.startsWith( FileInEglar.EGLAR_PREFIX ) ) { rest = rest.substring( FileInEglar.EGLAR_PREFIX.length() ); } int index = rest.lastIndexOf(FileInEglar.EGLAR_SEPARATOR); if (index == -1) return null; String src = rest.substring(0, index); rest = rest.substring(index + 1); String file= null; String extension= null; if(packageName != null && packageName.length() > 0){ //not in default package int ind = rest.lastIndexOf(PartInfo.SEPARATOR); if(ind == -1){ return null; } rest = rest.substring(ind + 1); //substract the package name } index = rest.lastIndexOf(PartInfo.EXTENSION_SEPARATOR); if(index == -1) return null; file= rest.substring(0, index); extension= rest.substring(index + 1); index = src.lastIndexOf(File.separator); String fileFolder = null; if(index != -1){ fileFolder = src.substring(0, index); src = src.substring(index + 1); } else{ return null; } if(project.startsWith(File.separator) || project.startsWith("/")){ project = project.substring(1); } return new PartDeclarationInfo(packageName, typeName, enclosingName, project, fileFolder, src, file, extension, partType, true); } private String getPackageName(char[] packageName) { if (fLast == null) return new String(packageName); char[] lastPackageName= fLast.getPackageName().toCharArray(); if (lastPackageName.equals(packageName)) return lastPackageName.toString(); return new String(packageName); } private String getProject(String path) { for (int i= 0; i < fProjects.length; i++) { String project= fProjects[i]; if (path.startsWith(project, 1)) return project; } return null; } private String createString(String s) { if (s == null) return null; int length= s.length(); if (length > fBuffer.length) fBuffer= new char[length]; s.getChars(0, length, fBuffer, 0); return new String(fBuffer, 0, length); } private static String[] getProjectList() { IEGLModel model= EGLCore.create(ResourcesPlugin.getWorkspace().getRoot()); String[] result; try { IEGLProject[] projects= model.getEGLProjects(); result= new String[projects.length]; for (int i= 0; i < projects.length; i++) { result[i]= projects[i].getElementName(); } } catch (EGLModelException e) { result= new String[0]; } // We have to sort the list of project names to make sure that we cut of the longest // project from the path, if two projects with the same prefix exist. For example // com.ibm.etools.egl.internal.model.ui and com.ibm.etools.egl.internal.model.ui.tests. Arrays.sort(result, new Comparator() { public int compare(Object o1, Object o2) { int l1= ((String)o1).length(); int l2= ((String)o2).length(); if (l1 < l2) return 1; if (l2 < l1) return -1; return 0; } public boolean equals(Object obj) { return super.equals(obj); } }); return result; } }