/*******************************************************************************
* 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();
}