blob: bdf28c67b44332df2e168b39c18c7138e86abb7c [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2005, 2017 IBM Corporation and others.
*
* This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0
* which accompanies this distribution, and is available at
* https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* IBM Corporation - initial API and implementation
*******************************************************************************/
package org.eclipse.pde.internal.core;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;
import org.eclipse.pde.internal.core.ifeature.IFeature;
import org.eclipse.pde.internal.core.ifeature.IFeatureModel;
/**
* Stores IFeatureModels. Models are indexed by id and id with version for fast
* retrieval. Given id or version may have more than one corresponding model. A
* model has only one id and version that can be null. When models changes, its
* Idver stays unchanged until the models reinserted.
*/
class FeatureTable {
public static class Idver {
private final String fId;
private final String fVer;
public Idver(String id, String version) {
fId = id;
fVer = version;
}
public String getId() {
return fId;
}
public String getVer() {
return fVer;
}
@Override
public int hashCode() {
int code = 0;
if (fId != null) {
code += fId.hashCode();
}
if (fVer != null) {
code += fVer.hashCode();
}
return code;
}
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (!(obj instanceof Idver)) {
return false;
}
return equals(((Idver) obj).getId(), ((Idver) obj).getVer());
}
public boolean equals(String id, String version) {
boolean sameId = fId == null && id == null || fId != null && fId.equals(id);
boolean sameVer = fVer == null && version == null || fVer != null && fVer.equals(version);
return sameId && sameVer;
}
@Override
public String toString() {
return fId + "_" + fVer; //$NON-NLS-1$
}
}
private static final IFeatureModel[] NO_MODELS = new IFeatureModel[0];
/**
* Map of IFeatureModel to Idver
*/
private final Map<IFeatureModel, Idver> fModel2idver;
/**
* Map of Idver to ArrayList of IFeatureModel
*/
private final Map<Idver, ArrayList<IFeatureModel>> fIdver2models;
/**
* Map of Id to ArrayList of Idver
*/
private final Map<String, ArrayList<Idver>> fId2idvers;
public FeatureTable() {
fModel2idver = new HashMap<>();
fIdver2models = new HashMap<>();
fId2idvers = new HashMap<>();
}
public synchronized Idver get(IFeatureModel model) {
return fModel2idver.get(model);
}
public synchronized IFeatureModel[] get(String id, String version) {
return getImpl(new Idver(id, version));
}
public synchronized IFeatureModel[] get(Idver idver) {
return getImpl(idver);
}
private IFeatureModel[] getImpl(Idver idver) {
ArrayList<IFeatureModel> models = fIdver2models.get(idver);
if (models == null) {
return NO_MODELS;
}
return models.toArray(new IFeatureModel[models.size()]);
}
public synchronized IFeatureModel[] get(String id) {
ArrayList<Idver> idvers = fId2idvers.get(id);
if (idvers == null) {
return NO_MODELS;
}
ArrayList<IFeatureModel> allModels = new ArrayList<>();
for (int i = 0; i < idvers.size(); i++) {
Idver idver = idvers.get(i);
ArrayList<IFeatureModel> models = fIdver2models.get(idver);
if (models == null) {
continue;
}
allModels.addAll(models);
}
return allModels.toArray(new IFeatureModel[allModels.size()]);
}
public synchronized IFeatureModel[] getAll() {
return getAllImpl();
}
private IFeatureModel[] getAllImpl() {
return fModel2idver.keySet().toArray(new IFeatureModel[fModel2idver.size()]);
}
/**
* Removes the model.
*
* @return Idver if model existed and was removed, null otherwise
*/
public synchronized Idver remove(IFeatureModel model) {
return removeImpl(model);
}
private Idver removeImpl(IFeatureModel model) {
Idver idver = fModel2idver.remove(model);
if (idver == null) {
return null;
}
ArrayList<IFeatureModel> models = fIdver2models.get(idver);
for (int i = 0; i < models.size(); i++) {
if (models.get(i) == model) {
models.remove(i);
break;
}
}
if (models.isEmpty()) {
fIdver2models.remove(idver);
ArrayList<Idver> idvers = fId2idvers.get(idver.getId());
for (int i = 0; i < idvers.size(); i++) {
if (idvers.get(i).equals(idver)) {
idvers.remove(i);
break;
}
}
if (idvers.isEmpty()) {
fId2idvers.remove(idver.getId());
}
}
return idver;
}
/**
* Adds the model. Updates the position of the model if already exist.
*
* @return Idver used during insertion
*/
public synchronized Idver add(IFeatureModel model) {
removeImpl(model);
IFeature feature = model.getFeature();
String id = feature.getId();
String ver = feature.getVersion();
Idver idver = new Idver(id, ver);
fModel2idver.put(model, idver);
ArrayList<IFeatureModel> models = fIdver2models.get(idver);
if (models == null) {
models = new ArrayList<>(1);
fIdver2models.put(idver, models);
}
models.add(model);
ArrayList<Idver> idvers = fId2idvers.get(id);
if (idvers == null) {
idvers = new ArrayList<>(1);
fId2idvers.put(id, idvers);
}
idvers.add(idver);
return idver;
}
@Override
public synchronized String toString() {
IFeatureModel[] models = getAllImpl();
StringBuilder buf = new StringBuilder(30 * models.length);
buf.append("["); //$NON-NLS-1$
for (int i = 0; i < models.length; i++) {
if (i > 0) {
buf.append(", "); //$NON-NLS-1$
}
buf.append(get(models[i]));
buf.append("@"); //$NON-NLS-1$
buf.append(models[i].getFeature().getId());
buf.append("_"); //$NON-NLS-1$
buf.append(models[i].getFeature().getVersion());
}
buf.append("]"); //$NON-NLS-1$
return buf.toString();
}
}