/******************************************************************************* * Copyright (c) 2006, 2015 Wind River Systems 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: * Wind River Systems - initial API and implementation *******************************************************************************/ package org.eclipse.cdt.dsf.datamodel; import org.eclipse.cdt.dsf.concurrent.Immutable; import org.eclipse.cdt.dsf.service.DsfSession; import org.eclipse.cdt.dsf.service.IDsfService; import org.eclipse.core.runtime.PlatformObject; /** * Base implementation of the IDMContext interface. There are two pieces of * functionality here: <br> * 1) The {@link #getAdapter(Class)} implementation which retrieves model * adapters registered with the session. <br> * 2) Methods to help compare DM Contexts. <br> * <p> * Note: The {@link #equals(Object)} and {@link #hashCode()} methods are * made abstract to force the deriving classes to provide a proper * implementation. Data Model Context objects are meant to be used as handles, * therefore a proper equals implementation is critical. * </p> * @param <V> Data Model data type that this context is for. * * @since 1.0 */ @Immutable abstract public class AbstractDMContext extends PlatformObject implements IDMContext { private final DsfSession fSession; private final IDMContext[] fParents; /** * Main constructor provides all data needed to implement the <code>IDMContext</code> * interface. * @since 2.2 */ public AbstractDMContext(DsfSession session, IDMContext[] parents) { fSession = session; fParents = parents; for (IDMContext parent : parents) { assert(parent != null); } } /** Convenience constructor */ public AbstractDMContext(IDsfService service, IDMContext[] parents) { this(service.getSession(), parents); } /** Backward compatibility constructor */ public AbstractDMContext(String fSessionId, IDMContext[] parents) { this(DsfSession.getSession(fSessionId), parents); } /** * Should be used by the deriving class to compare the basic context object * information. * @param other the other service to compare to * @return true if contexts are equal */ protected boolean baseEquals(Object other) { if (other == null) return false; if ( !(other.getClass().equals(getClass()))) return false; IDMContext otherCtx = (IDMContext)other; return getSessionId().equals(otherCtx.getSessionId()) && areParentsEqual(otherCtx.getParents()); } private boolean areParentsEqual(IDMContext[] otherParents) { IDMContext[] parents = getParents(); if ( !(parents.length == otherParents.length) ) return false; for (int i = 0; i < parents.length; i++) { if (!parents[i].equals(otherParents[i])) { return false; } } return true; } protected int baseHashCode() { int parentsHash = 0; for (Object parent : getParents()) { parentsHash += parent.hashCode(); } return getSessionId().hashCode() + parentsHash; } /** * @return a stringified representation of our parent context. If we have * more than one parent, the parents are separated by commas, and * the entire collection is wrapped with parenthesis: * "(p1,p2,...,pn)" */ protected String baseToString() { StringBuilder retVal = new StringBuilder(); for (IDMContext parent : getParents()) { retVal.append(parent); retVal.append(','); } if (retVal.length() > 0) { retVal.deleteCharAt(retVal.length() - 1); // remove trailing comma } if (getParents().length > 1) { retVal.insert(0, '('); retVal.insert(retVal.length(), ')'); } return retVal.toString(); } @Override public String getSessionId() { return fSession.getId(); } @Override public IDMContext[] getParents() { return fParents; } /** * Overrides the standard platform getAdapter to provide session-specific * adapters. * <p> * ModelContext is intended to be used in views, which call the * contexts.getAdapter() method to retrieve model-specific content and * label providers. But since many different sessions could be active * at the same time, each requiring different content providers, the * standard platform <code>IAdapterManager</code> is not sufficient in * handling adapters for the model context object. This is because * <code>IAdapterManager</code> uses only the class of the adaptable to * select the correct adapter factory, while for model context, the * session is equally important. * @see org.eclipse.runtime.IAdapterManager */ @SuppressWarnings("unchecked") @Override public <T> T getAdapter(Class<T> adapterType) { T retVal = (T)fSession.getModelAdapter(adapterType); if (retVal == null) { retVal = super.getAdapter(adapterType); } return retVal; } /** * Deriving classes must implement proper equals and hashCode operations * based on context data. */ @Override abstract public boolean equals(Object obj); /** * Deriving classes must implement proper equals and hashCode operations * based on context data. */ @Override abstract public int hashCode(); }