/******************************************************************************* * Copyright (c) 2007, 2017 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 * Cloudsmith Inc. - query indexes * ******************************************************************************/ package org.eclipse.equinox.internal.p2.engine; import java.util.*; import java.util.Map.Entry; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.core.runtime.NullProgressMonitor; import org.eclipse.equinox.internal.p2.core.helpers.OrderedProperties; import org.eclipse.equinox.internal.p2.metadata.*; import org.eclipse.equinox.internal.p2.metadata.index.*; import org.eclipse.equinox.p2.core.IProvisioningAgent; import org.eclipse.equinox.p2.engine.IProfile; import org.eclipse.equinox.p2.metadata.IInstallableUnit; import org.eclipse.equinox.p2.metadata.KeyWithLocale; import org.eclipse.equinox.p2.metadata.expression.IEvaluationContext; import org.eclipse.equinox.p2.metadata.expression.IExpression; import org.eclipse.equinox.p2.metadata.index.IIndex; import org.eclipse.equinox.p2.query.IQuery; import org.eclipse.equinox.p2.query.IQueryResult; import org.eclipse.osgi.util.NLS; public class Profile extends IndexProvider<IInstallableUnit> implements IProfile { /** * An index that limits the candidates to those units that has profile properties */ class ProfilePropertyIndex implements IIndex<IInstallableUnit> { @Override public Iterator<IInstallableUnit> getCandidates(IEvaluationContext ctx, IExpression variable, IExpression booleanExpr) { return iuProperties.keySet().iterator(); } } private final IProvisioningAgent agent; //Internal id of the profile private final String profileId; private Profile parentProfile; private IIndex<IInstallableUnit> idIndex; private IIndex<IInstallableUnit> propertiesIndex; private IIndex<IInstallableUnit> capabilityIndex; private TranslationSupport translationSupport; /** * A collection of child profiles. */ private List<String> subProfileIds; // child profile ids /** * This storage is to be used by the touchpoints to store data. */ private OrderedProperties storage = new OrderedProperties(); private IUMap ius = new IUMap(); final Map<IInstallableUnit, OrderedProperties> iuProperties = new HashMap<>(); private boolean changed = false; private long timestamp; private ISurrogateProfileHandler surrogateProfileHandler; public Profile(IProvisioningAgent agent, String profileId, Profile parent, Map<String, String> properties) { this.agent = agent; if (profileId == null || profileId.length() == 0) { throw new IllegalArgumentException(NLS.bind(Messages.Profile_Null_Profile_Id, null)); } this.profileId = profileId; setParent(parent); if (properties != null) storage.putAll(properties); } @Override public String getProfileId() { return profileId; } public IProfile getParentProfile() { return parentProfile; } public void setParent(Profile profile) { if (profile == parentProfile) return; if (parentProfile != null) parentProfile.removeSubProfile(profileId); parentProfile = profile; if (parentProfile != null) parentProfile.addSubProfile(profileId); } /* * A profile is a root profile if it is not a sub-profile * of another profile. */ public boolean isRootProfile() { return parentProfile == null; } public void addSubProfile(String subProfileId) throws IllegalArgumentException { if (subProfileIds == null) subProfileIds = new ArrayList<>(); if (!subProfileIds.contains(subProfileId)) subProfileIds.add(subProfileId); // if (!subProfileIds.add(subProfileId)) // throw new IllegalArgumentException(NLS.bind(Messages.Profile_Duplicate_Child_Profile_Id, new String[] {subProfileId, this.getProfileId()})); } public void removeSubProfile(String subProfileId) throws IllegalArgumentException { if (subProfileIds != null) subProfileIds.remove(subProfileId); } public boolean hasSubProfiles() { return subProfileIds != null && !subProfileIds.isEmpty(); } public List<String> getSubProfileIds() { if (subProfileIds == null) return Collections.<String> emptyList(); return Collections.unmodifiableList(subProfileIds); } @Override public String getProperty(String key) { String value = getLocalProperty(key); if (value == null && parentProfile != null) { value = parentProfile.getProperty(key); } return value; } public String getLocalProperty(String key) { return storage.getProperty(key); } /** * Associate the given value with the given key * in the local storage of this profile. */ public void setProperty(String key, String value) { storage.setProperty(key, value); changed = true; } public void removeProperty(String key) { storage.remove(key); changed = true; } @Override public synchronized IIndex<IInstallableUnit> getIndex(String memberName) { if (InstallableUnit.MEMBER_ID.equals(memberName)) { if (idIndex == null) idIndex = new IdIndex(ius); return idIndex; } if (InstallableUnit.MEMBER_PROVIDED_CAPABILITIES.equals(memberName)) { if (capabilityIndex == null) capabilityIndex = new CapabilityIndex(ius.iterator()); return capabilityIndex; } if (InstallableUnit.MEMBER_PROFILE_PROPERTIES.equals(memberName)) { if (propertiesIndex == null) propertiesIndex = new ProfilePropertyIndex(); return propertiesIndex; } return null; } @Override public Iterator<IInstallableUnit> everything() { return ius.iterator(); } @Override public Object getManagedProperty(Object client, String memberName, Object key) { if (!(client instanceof IInstallableUnit)) return null; IInstallableUnit iu = (IInstallableUnit) client; if (InstallableUnit.MEMBER_PROFILE_PROPERTIES.equals(memberName) && key instanceof String) return getInstallableUnitProperty(iu, (String) key); if (InstallableUnit.MEMBER_TRANSLATED_PROPERTIES.equals(memberName)) { synchronized (this) { if (translationSupport == null) translationSupport = new TranslationSupport(this); return key instanceof KeyWithLocale ? translationSupport.getIUProperty(iu, (KeyWithLocale) key) : translationSupport.getIUProperty(iu, key.toString()); } } return null; } @Override public IQueryResult<IInstallableUnit> available(IQuery<IInstallableUnit> query, IProgressMonitor monitor) { if (surrogateProfileHandler != null) return surrogateProfileHandler.queryProfile(this, query, monitor); return query(query, new NullProgressMonitor()); } @Override public String getInstallableUnitProperty(IInstallableUnit iu, String key) { OrderedProperties properties = iuProperties.get(iu); if (properties == null) return null; return properties.getProperty(key); } public String setInstallableUnitProperty(IInstallableUnit iu, String key, String value) { // String iuKey = createIUKey(iu); OrderedProperties properties = iuProperties.get(iu); if (properties == null) { properties = new OrderedProperties(); iuProperties.put(iu, properties); } changed = true; return (String) properties.setProperty(key, value); } public String removeInstallableUnitProperty(IInstallableUnit iu, String key) { // String iuKey = createIUKey(iu); OrderedProperties properties = iuProperties.get(iu); if (properties == null) return null; String oldValue = properties.remove(key); if (properties.isEmpty()) iuProperties.remove(iu); changed = true; return oldValue; } // private static String createIUKey(IInstallableUnit iu) { // return iu.getId() + "_" + iu.getVersion().toString(); //$NON-NLS-1$ // } public Map<String, String> getLocalProperties() { return OrderedProperties.unmodifiableProperties(storage); } @Override public Map<String, String> getProperties() { if (parentProfile == null) return getLocalProperties(); Map<String, String> properties = new HashMap<>(parentProfile.getProperties()); properties.putAll(storage); return OrderedProperties.unmodifiableProperties(properties); } @Override public IProvisioningAgent getProvisioningAgent() { return agent; } /** * Add all the properties in the map to the local properties * of the profile. */ public void addProperties(Map<String, String> properties) { storage.putAll(properties); changed = true; } public void addInstallableUnit(IInstallableUnit iu) { iu = iu.unresolved(); if (ius.contains(iu)) return; ius.add(iu); changed = true; } public void removeInstallableUnit(IInstallableUnit iu) { iu = iu.unresolved(); ius.remove(iu); changed = true; } @Override public Map<String, String> getInstallableUnitProperties(IInstallableUnit iu) { OrderedProperties properties = iuProperties.get(iu); if (properties == null) properties = new OrderedProperties(); return OrderedProperties.unmodifiableProperties(properties); } public void clearLocalProperties() { storage.clear(); changed = true; } public boolean isChanged() { return changed; } public void setChanged(boolean isChanged) { changed = isChanged; } public void clearInstallableUnits() { ius.clear(); iuProperties.clear(); changed = true; } public Profile snapshot() { Profile parentSnapshot = null; if (parentProfile != null) parentSnapshot = parentProfile.snapshot(); Profile snapshot = new Profile(agent, profileId, parentSnapshot, storage); if (surrogateProfileHandler != null) snapshot.setSurrogateProfileHandler(surrogateProfileHandler); snapshot.setTimestamp(timestamp); if (subProfileIds != null) { for (String subProfileId : subProfileIds) { snapshot.addSubProfile(subProfileId); } } for (Iterator<IInstallableUnit> iter = ius.iterator(); iter.hasNext();) { IInstallableUnit iu = iter.next(); snapshot.addInstallableUnit(iu); Map<String, String> properties = getInstallableUnitProperties(iu); if (properties != null) snapshot.addInstallableUnitProperties(iu, properties); } snapshot.setChanged(false); return snapshot; } public void addInstallableUnitProperties(IInstallableUnit iu, Map<String, String> properties) { for (Entry<String, String> entry : properties.entrySet()) { setInstallableUnitProperty(iu, entry.getKey(), entry.getValue()); } } public void clearInstallableUnitProperties(IInstallableUnit iu) { iuProperties.remove(iu); changed = true; } public void clearOrphanedInstallableUnitProperties() { Set<IInstallableUnit> keys = iuProperties.keySet(); // Set orphans = new HashSet(); Collection<IInstallableUnit> toRemove = new ArrayList<>(); for (IInstallableUnit iu : keys) { if (!ius.contains(iu)) toRemove.add(iu); } for (IInstallableUnit iu : toRemove) { iuProperties.remove(iu); } // List iuKeys = new ArrayList(); // for (Iterator it = ius.iterator(); it.hasNext();) // iuKeys.add((IInstallableUnit) it.next()); // // iuProperties.keySet().retainAll(iuKeys); } @Override public long getTimestamp() { return timestamp; } public void setTimestamp(long millis) { timestamp = millis; } public void setSurrogateProfileHandler(ISurrogateProfileHandler surrogateProfileHandler) { this.surrogateProfileHandler = surrogateProfileHandler; } /** * Prints a string representation for debugging purposes only. */ @Override public String toString() { return "Profile(" + getProfileId() + ')'; //$NON-NLS-1$ } }