| /******************************************************************************* |
| * Copyright (c) 2005, 2016 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 |
| * |
| * sbernard@sierrawireless.com - fix for Bug 361231 - Bad Memento serialization with external Zip projet fragment |
| *******************************************************************************/ |
| package org.eclipse.dltk.internal.core; |
| |
| import java.util.ArrayList; |
| import java.util.Enumeration; |
| import java.util.List; |
| import java.util.Map; |
| |
| import org.eclipse.core.resources.IResource; |
| import org.eclipse.core.resources.ResourcesPlugin; |
| import org.eclipse.core.runtime.CoreException; |
| import org.eclipse.core.runtime.IPath; |
| import org.eclipse.core.runtime.Path; |
| import org.eclipse.dltk.compiler.CharOperation; |
| import org.eclipse.dltk.core.DLTKLanguageManager; |
| import org.eclipse.dltk.core.IArchive; |
| import org.eclipse.dltk.core.IArchiveEntry; |
| import org.eclipse.dltk.core.IDLTKLanguageToolkit; |
| import org.eclipse.dltk.core.IModelElement; |
| import org.eclipse.dltk.core.IModelProvider; |
| import org.eclipse.dltk.core.IProjectFragment; |
| import org.eclipse.dltk.core.IScriptFolder; |
| import org.eclipse.dltk.core.ModelException; |
| import org.eclipse.dltk.core.environment.EnvironmentManager; |
| import org.eclipse.dltk.core.environment.EnvironmentPathUtils; |
| import org.eclipse.dltk.core.environment.IEnvironment; |
| import org.eclipse.dltk.internal.core.util.HashtableOfArrayToObject; |
| import org.eclipse.dltk.internal.core.util.Util; |
| |
| public class ArchiveProjectFragment extends ProjectFragment { |
| public final static ArrayList EMPTY_LIST = new ArrayList(); |
| /** |
| * The path to the zip file (a workspace relative path if the archive is |
| * internal, or an OS path if the archive is external) |
| */ |
| protected final IPath zipPath; |
| protected final IResource zipResource; |
| private IArchive archive; |
| |
| protected ArchiveProjectFragment(IResource resource, ScriptProject project) { |
| super(resource, project); |
| zipPath = resource.getFullPath(); |
| this.zipResource = resource; |
| } |
| |
| protected ArchiveProjectFragment(IPath path, ScriptProject project) { |
| super(null, project); |
| zipPath = path; |
| this.zipResource = null; |
| } |
| |
| /** |
| * Compute the package fragment children of this package fragment root. |
| * These are all of the directory zip entries, and any directories implied |
| * by the path of class files contained in the archive of this package |
| * fragment root. Has the side effect of opening the package fragment |
| * children. |
| */ |
| @Override |
| protected boolean computeChildren(OpenableElementInfo info, Map newElements) |
| throws ModelException { |
| ArrayList vChildren = new ArrayList(); |
| final int SCRIPT = 0; |
| final int NON_SCRIPT = 1; |
| archive = null; |
| try { |
| archive = ModelManager.getModelManager() |
| .getArchive(getPath(), this); |
| HashtableOfArrayToObject packageFragToTypes = new HashtableOfArrayToObject(); |
| // always create the default package |
| packageFragToTypes.put(CharOperation.NO_STRINGS, new ArrayList[] { |
| EMPTY_LIST, EMPTY_LIST }); |
| for (Enumeration<? extends IArchiveEntry> e = archive |
| .getArchiveEntries(); e.hasMoreElements();) { |
| IArchiveEntry member = e.nextElement(); |
| initPackageFragToTypes(packageFragToTypes, member.getName(), |
| member.isDirectory()); |
| } |
| // loop through all of referenced packages, creating package |
| // fragments if necessary |
| // and cache the entry names in the infos created for those package |
| // fragments |
| for (int i = 0, length = packageFragToTypes.keyTable.length; i < length; i++) { |
| String[] pkgName = (String[]) packageFragToTypes.keyTable[i]; |
| if (pkgName == null) |
| continue; |
| ArrayList[] entries = (ArrayList[]) packageFragToTypes |
| .get(pkgName); |
| String path = ""; //$NON-NLS-1$ |
| if (pkgName.length >= 1) { |
| path = pkgName[0]; |
| for (int e = 1; e < pkgName.length; ++e) { |
| path += Path.SEPARATOR + pkgName[e]; |
| } |
| } |
| Path lpath = new Path(path); |
| ArchiveFolder packFrag = (ArchiveFolder) getScriptFolder(lpath); |
| ArchiveFolderInfo fragInfo = new ArchiveFolderInfo(); |
| int resLength = entries[NON_SCRIPT].size(); |
| if (resLength == 0) { |
| packFrag.computeForeignResources(CharOperation.NO_STRINGS, |
| fragInfo, archive.getName()); |
| } else { |
| String[] resNames = new String[resLength]; |
| entries[NON_SCRIPT].toArray(resNames); |
| packFrag.computeForeignResources(resNames, fragInfo, |
| archive.getName()); |
| } |
| if (lpath.segmentCount() == 0) { |
| ((ArchiveProjectFragmentInfo) info) |
| .setForeignResources(fragInfo.foreignResources); |
| } |
| packFrag.computeChildren(fragInfo, entries[SCRIPT]); |
| newElements.put(packFrag, fragInfo); |
| vChildren.add(packFrag); |
| } |
| } catch (CoreException e) { |
| if (e instanceof ModelException) |
| throw (ModelException) e; |
| throw new ModelException(e); |
| } finally { |
| ModelManager.getModelManager().closeArchive(archive); |
| } |
| // IModelElement[] children = new IModelElement[vChildren.size()]; |
| // vChildren.toArray(children); |
| // info.setChildren(children); |
| List childrenSet = vChildren; |
| // Call for extra model providers |
| IDLTKLanguageToolkit toolkit = DLTKLanguageManager |
| .getLanguageToolkit(this); |
| IModelProvider[] providers = ModelProviderManager.getProviders(toolkit |
| .getNatureId()); |
| if (providers != null) { |
| for (int i = 0; i < providers.length; i++) { |
| providers[i].provideModelChanges(this, childrenSet); |
| } |
| } |
| info.setChildren((IModelElement[]) childrenSet |
| .toArray(new IModelElement[childrenSet.size()])); |
| return true; |
| } |
| |
| @Override |
| public IScriptFolder getScriptFolder(IPath path) { |
| return new ArchiveFolder(this, path); |
| } |
| |
| public String getZipName() { |
| IEnvironment environment = EnvironmentManager |
| .getEnvironment(getScriptProject()); |
| return environment.convertPathToString(this.zipPath); |
| } |
| |
| private void initPackageFragToTypes( |
| HashtableOfArrayToObject packageFragToTypes, String entryName, |
| boolean isDirectory) { |
| int lastSeparator = isDirectory ? entryName.length() - 1 : entryName |
| .lastIndexOf('/'); |
| String[] pkgName = Util.splitOn('/', entryName, 0, lastSeparator); |
| String[] existing = null; |
| int length = pkgName.length; |
| int existingLength = length; |
| while (existingLength >= 0) { |
| existing = (String[]) packageFragToTypes.getKey(pkgName, |
| existingLength); |
| if (existing != null) |
| break; |
| existingLength--; |
| } |
| ModelManager manager = ModelManager.getModelManager(); |
| for (int i = existingLength; i < length; i++) { |
| if (Util.isValidFolderNameForPackage(pkgName[i])) { |
| System.arraycopy(existing, 0, existing = new String[i + 1], 0, |
| i); |
| existing[i] = manager.intern(pkgName[i]); |
| packageFragToTypes.put(existing, new ArrayList[] { EMPTY_LIST, |
| EMPTY_LIST }); |
| } else { |
| // non-script resource folder |
| if (!isDirectory) { |
| ArrayList[] children = (ArrayList[]) packageFragToTypes |
| .get(existing); |
| if (children[1/* NON_SCRIPT */] == EMPTY_LIST) |
| children[1/* NON_SCRIPT */] = new ArrayList(); |
| children[1/* NON_SCRIPT */].add(entryName); |
| } |
| return; |
| } |
| } |
| if (isDirectory) |
| return; |
| // add classfile info amongst children |
| ArrayList[] children = (ArrayList[]) packageFragToTypes.get(pkgName); |
| if (Util.isValidSourceModuleName(getScriptProject(), entryName)) { |
| if (children[0/* SCRIPT */] == EMPTY_LIST) |
| children[0/* SCRIPT */] = new ArrayList(); |
| String fileName = entryName.substring(lastSeparator + 1); |
| children[0/* SCRIPT */].add(fileName); |
| } else { |
| if (children[1/* NON_SCRIPT */] == EMPTY_LIST) |
| children[1/* NON_SCRIPT */] = new ArrayList(); |
| children[1/* NON_SCRIPT */].add(entryName); |
| } |
| } |
| |
| @Override |
| public boolean isReadOnly() { |
| return true; |
| } |
| |
| @Override |
| protected Object createElementInfo() { |
| return new ArchiveProjectFragmentInfo(); |
| } |
| |
| @Override |
| public boolean isArchive() { |
| return true; |
| } |
| |
| @Override |
| public boolean isExternal() { |
| return getResource() == null; |
| } |
| |
| @Override |
| public IResource getUnderlyingResource() throws ModelException { |
| if (isExternal()) { |
| if (!exists()) { |
| throw newNotPresentException(); |
| } |
| return null; |
| } else { |
| return super.getUnderlyingResource(); |
| } |
| } |
| |
| @Override |
| public int hashCode() { |
| return this.zipPath.hashCode(); |
| } |
| |
| @Override |
| public IPath getPath() { |
| return zipPath; |
| } |
| |
| @Override |
| public IResource getResource() { |
| if (this.resource == null) { |
| this.resource = Model.getTarget(ResourcesPlugin.getWorkspace() |
| .getRoot(), this.zipPath, false); |
| } |
| if (this.resource instanceof IResource) { |
| return super.getResource(); |
| } else { |
| // external archive |
| return null; |
| } |
| } |
| |
| /** |
| * Returns whether the corresponding resource or associated file exists |
| */ |
| @Override |
| protected boolean resourceExists() { |
| if (this.isExternal()) { |
| /* |
| * don't make the path relative as this is an external archive |
| */ |
| return Model.getTarget(ResourcesPlugin.getWorkspace().getRoot(), |
| this.getPath(), true) != null; |
| } else { |
| return super.resourceExists(); |
| } |
| } |
| |
| @Override |
| protected void toStringAncestors(StringBuffer buffer) { |
| if (isExternal()) |
| return; |
| super.toStringAncestors(buffer); |
| } |
| |
| @Override |
| public int getKind() { |
| return IProjectFragment.K_SOURCE; |
| } |
| |
| @Override |
| public boolean equals(Object o) { |
| if (this == o) |
| return true; |
| if (o instanceof ArchiveProjectFragment) { |
| ArchiveProjectFragment other = (ArchiveProjectFragment) o; |
| return this.zipPath.equals(other.zipPath); |
| } |
| return false; |
| } |
| |
| public IArchive getArchive() { |
| return archive; |
| } |
| |
| @Override |
| public String getElementName() { |
| if (isExternal()) { |
| IEnvironment env = EnvironmentManager.getEnvironment(this); |
| if (env == null) { |
| env = EnvironmentPathUtils.getPathEnvironment(this.zipPath); |
| } |
| String pathString = EnvironmentPathUtils |
| .getLocalPathString(this.zipPath); |
| if (env != null && pathString != null) { |
| return pathString.replace(env.getSeparatorChar(), |
| JEM_SKIP_DELIMETER); |
| } |
| } |
| return this.zipPath.lastSegment(); |
| } |
| |
| @Override |
| public void getHandleMemento(StringBuffer buff) { |
| ((ModelElement) getParent()).getHandleMemento(buff); |
| buff.append(getHandleMementoDelimiter()); |
| escapeMementoName(buff, getElementName()); |
| } |
| |
| } |