1 /******************************************************************************* 2 * Copyright (c) 2000, 2015 IBM Corporation and others. 3 * 4 * This program and the accompanying materials 5 * are made available under the terms of the Eclipse Public License 2.0 6 * which accompanies this distribution, and is available at 7 * https://www.eclipse.org/legal/epl-2.0/ 8 * 9 * SPDX-License-Identifier: EPL-2.0 10 * 11 * Contributors: 12 * IBM Corporation - initial API and implementation 13 * Baltasar Belyavsky (Texas Instruments) - [361675] Order mismatch when saving/restoring workspace trees 14 * Broadcom Corporation - ongoing development 15 * Lars Vogel <Lars.Vogel@vogella.com> - Bug 473427 16 *******************************************************************************/ 17 package org.eclipse.core.internal.resources; 18 19 import java.io.DataInputStream; 20 import java.io.IOException; 21 import java.util.*; 22 import org.eclipse.core.internal.events.BuilderPersistentInfo; 23 import org.eclipse.core.internal.utils.Messages; 24 import org.eclipse.core.internal.utils.Policy; 25 import org.eclipse.core.internal.watson.ElementTree; 26 import org.eclipse.core.resources.IProject; 27 import org.eclipse.core.resources.IResourceStatus; 28 import org.eclipse.core.runtime.*; 29 30 /** 31 * Reads version 2 of the workspace tree file format. 32 * 33 * This version differs from version 1 in the amount of information that is persisted 34 * for each builder. Version 1 only stored builder names and trees. Version 35 * 2 stores builder names, project names, trees, and interesting projects for 36 * each builder. 37 * <p> 38 * Since 3.7 support has been added for persisting multiple delta trees for 39 * multi-configuration builders. 40 * </p> 41 * <p> 42 * To achieve backwards compatibility, the new additional information is 43 * appended to the existing workspace tree file. This allows the workspace 44 * to be opened, and function, with older eclipse products. 45 * </p> 46 */ 47 public class WorkspaceTreeReader_2 extends WorkspaceTreeReader_1 { 48 49 private List<BuilderPersistentInfo> builderInfos; 50 WorkspaceTreeReader_2(Workspace workspace)51 public WorkspaceTreeReader_2(Workspace workspace) { 52 super(workspace); 53 } 54 55 @Override getVersion()56 protected int getVersion() { 57 return ICoreConstants.WORKSPACE_TREE_VERSION_2; 58 } 59 60 /* 61 * overwritten from WorkspaceTreeReader_1 62 */ 63 @Override readBuildersPersistentInfo(IProject project, DataInputStream input, List<BuilderPersistentInfo> builders, IProgressMonitor monitor)64 protected void readBuildersPersistentInfo(IProject project, DataInputStream input, List<BuilderPersistentInfo> builders, IProgressMonitor monitor) throws IOException { 65 monitor = Policy.monitorFor(monitor); 66 try { 67 int builderCount = input.readInt(); 68 for (int i = 0; i < builderCount; i++) { 69 BuilderPersistentInfo info = readBuilderInfo(project, input, i); 70 // read interesting projects 71 int n = input.readInt(); 72 IProject[] projects = new IProject[n]; 73 for (int j = 0; j < n; j++) 74 projects[j] = workspace.getRoot().getProject(input.readUTF()); 75 info.setInterestingProjects(projects); 76 builders.add(info); 77 } 78 } finally { 79 monitor.done(); 80 } 81 } 82 83 /** 84 * Read a workspace tree storing information about multiple projects. 85 * Overrides {@link WorkspaceTreeReader_1#readTree(DataInputStream, IProgressMonitor)} 86 */ 87 @Override readTree(DataInputStream input, IProgressMonitor monitor)88 public void readTree(DataInputStream input, IProgressMonitor monitor) throws CoreException { 89 monitor = Policy.monitorFor(monitor); 90 String message; 91 try { 92 message = Messages.resources_reading; 93 monitor.beginTask(message, Policy.totalWork); 94 95 builderInfos = new ArrayList<>(20); 96 97 // Read the version 2 part of the file, but don't set the builder info in 98 // the projects. Store it in builderInfos instead. 99 readWorkspaceFields(input, Policy.subMonitorFor(monitor, Policy.opWork * 20 / 100)); 100 101 HashMap<String, SavedState> savedStates = new HashMap<>(20); 102 List<SavedState> pluginsToBeLinked = new ArrayList<>(20); 103 readPluginsSavedStates(input, savedStates, pluginsToBeLinked, Policy.subMonitorFor(monitor, Policy.opWork * 10 / 100)); 104 workspace.getSaveManager().setPluginsSavedState(savedStates); 105 106 int treeIndex = pluginsToBeLinked.size(); 107 108 List<BuilderPersistentInfo> buildersToBeLinked = new ArrayList<>(20); 109 readBuildersPersistentInfo(null, input, buildersToBeLinked, Policy.subMonitorFor(monitor, Policy.opWork * 10 / 100)); 110 111 final ElementTree[] trees = readTrees(Path.ROOT, input, Policy.subMonitorFor(monitor, Policy.opWork * 40 / 100)); 112 linkPluginsSavedStateToTrees(pluginsToBeLinked, trees, Policy.subMonitorFor(monitor, Policy.opWork * 10 / 100)); 113 linkBuildersToTrees(buildersToBeLinked, trees, treeIndex, Policy.subMonitorFor(monitor, Policy.opWork * 10 / 100)); 114 115 // Since 3.7: Read the per-configuration trees if available 116 if (input.available() > 0) { 117 treeIndex += buildersToBeLinked.size(); 118 119 buildersToBeLinked.clear(); 120 readBuildersPersistentInfo(null, input, buildersToBeLinked, Policy.subMonitorFor(monitor, Policy.opWork * 10 / 100)); 121 linkBuildersToTrees(buildersToBeLinked, trees, treeIndex, Policy.subMonitorFor(monitor, Policy.opWork * 10 / 100)); 122 123 for (BuilderPersistentInfo builderPersistentInfo : builderInfos) 124 builderPersistentInfo.setConfigName(input.readUTF()); 125 } 126 127 // Set the builder infos on the projects 128 setBuilderInfos(builderInfos); 129 130 } catch (IOException e) { 131 message = Messages.resources_readProjectTree; 132 throw new ResourceException(IResourceStatus.FAILED_READ_METADATA, null, message, e); 133 } finally { 134 monitor.done(); 135 } 136 } 137 138 /** 139 * Read a workspace tree storing information about a single project. 140 * Overrides {@link WorkspaceTreeReader_2#readTree(IProject, DataInputStream, IProgressMonitor)} 141 */ 142 @Override readTree(IProject project, DataInputStream input, IProgressMonitor monitor)143 public void readTree(IProject project, DataInputStream input, IProgressMonitor monitor) throws CoreException { 144 monitor = Policy.monitorFor(monitor); 145 String message; 146 try { 147 message = Messages.resources_reading; 148 monitor.beginTask(message, 10); 149 150 builderInfos = new ArrayList<>(20); 151 152 // Read the version 2 part of the file, but don't set the builder info in 153 // the projects. It is stored in builderInfos instead. 154 155 int treeIndex = 0; 156 157 List<BuilderPersistentInfo> buildersToBeLinked = new ArrayList<>(20); 158 readBuildersPersistentInfo(project, input, buildersToBeLinked, Policy.subMonitorFor(monitor, 1)); 159 160 ElementTree[] trees = readTrees(project.getFullPath(), input, Policy.subMonitorFor(monitor, 8)); 161 linkBuildersToTrees(buildersToBeLinked, trees, treeIndex, Policy.subMonitorFor(monitor, 1)); 162 163 // Since 3.7: Read the additional builder information 164 if (input.available() > 0) { 165 treeIndex += buildersToBeLinked.size(); 166 167 List<BuilderPersistentInfo> infos = new ArrayList<>(5); 168 readBuildersPersistentInfo(project, input, infos, Policy.subMonitorFor(monitor, 1)); 169 linkBuildersToTrees(infos, trees, treeIndex, Policy.subMonitorFor(monitor, 1)); 170 171 for (BuilderPersistentInfo builderPersistentInfo : builderInfos) 172 builderPersistentInfo.setConfigName(input.readUTF()); 173 } 174 175 // Set the builder info on the projects 176 setBuilderInfos(builderInfos); 177 178 } catch (IOException e) { 179 message = Messages.resources_readProjectTree; 180 throw new ResourceException(IResourceStatus.FAILED_READ_METADATA, null, message, e); 181 } finally { 182 monitor.done(); 183 } 184 } 185 186 /** 187 * This implementation allows pre-3.7 version 2 and post-3.7 version 2 information to be loaded in separate passes. 188 * Links trees with the given builders, but does not add them to the projects. 189 * Overrides {@link WorkspaceTreeReader_1#linkBuildersToTrees(List, ElementTree[], int, IProgressMonitor)} 190 */ 191 @Override linkBuildersToTrees(List<BuilderPersistentInfo> buildersToBeLinked, ElementTree[] trees, int index, IProgressMonitor monitor)192 protected void linkBuildersToTrees(List<BuilderPersistentInfo> buildersToBeLinked, ElementTree[] trees, int index, IProgressMonitor monitor) { 193 monitor = Policy.monitorFor(monitor); 194 try { 195 for (int i = 0; i < buildersToBeLinked.size(); i++) { 196 BuilderPersistentInfo info = buildersToBeLinked.get(i); 197 info.setLastBuildTree(trees[index++]); 198 builderInfos.add(info); 199 } 200 } finally { 201 monitor.done(); 202 } 203 } 204 205 /** 206 * Given a list of builder infos, group them by project and set them on the project. 207 */ setBuilderInfos(List<BuilderPersistentInfo> infos)208 private void setBuilderInfos(List<BuilderPersistentInfo> infos) { 209 Map<String, List<BuilderPersistentInfo>> groupedInfos = new HashMap<>(); 210 for (BuilderPersistentInfo info : infos) { 211 if (!groupedInfos.containsKey(info.getProjectName())) 212 groupedInfos.put(info.getProjectName(), new ArrayList<>()); 213 groupedInfos.get(info.getProjectName()).add(info); 214 } 215 for (Map.Entry<String, List<BuilderPersistentInfo>> entry : groupedInfos.entrySet()) { 216 IProject proj = workspace.getRoot().getProject(entry.getKey()); 217 workspace.getBuildManager().setBuildersPersistentInfo(proj, entry.getValue()); 218 } 219 } 220 221 } 222