/******************************************************************************* * Copyright (c) 2006 Oracle Corporation. * 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: * Cameron Bateman/Oracle - initial API and implementation * ********************************************************************************/ package org.eclipse.jst.jsf.context.symbol.internal.impl; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Set; import java.util.StringTokenizer; import org.eclipse.emf.common.notify.Notification; import org.eclipse.emf.common.util.BasicEList; import org.eclipse.emf.common.util.ECollections; import org.eclipse.emf.common.util.EList; import org.eclipse.emf.ecore.EClass; import org.eclipse.emf.ecore.impl.ENotificationImpl; import org.eclipse.jdt.core.IType; import org.eclipse.jdt.core.Signature; import org.eclipse.jst.jsf.common.internal.types.TypeConstants; import org.eclipse.jst.jsf.context.symbol.IInstanceSymbol; import org.eclipse.jst.jsf.context.symbol.IJavaTypeDescriptor2; import org.eclipse.jst.jsf.context.symbol.IMapTypeDescriptor; import org.eclipse.jst.jsf.context.symbol.IObjectSymbol; import org.eclipse.jst.jsf.context.symbol.IPropertySymbol; import org.eclipse.jst.jsf.context.symbol.ITypeDescriptor; import org.eclipse.jst.jsf.context.symbol.SymbolFactory; import org.eclipse.jst.jsf.context.symbol.SymbolPackage; /** * <!-- begin-user-doc --> * An implementation of the model object '<em><b>IMap Type Descriptor</b></em>'. * <!-- end-user-doc --> * <p> * The following features are implemented: * <ul> * <li>{@link org.eclipse.jst.jsf.context.symbol.internal.impl.IMapTypeDescriptorImpl#getMapSource <em>Map Source</em>}</li> * <li>{@link org.eclipse.jst.jsf.context.symbol.internal.impl.IMapTypeDescriptorImpl#isImmutable <em>Immutable</em>}</li> * </ul> * </p> * * @generated */ public class IMapTypeDescriptorImpl extends ITypeDescriptorImpl implements IMapTypeDescriptor { /** * <!-- begin-user-doc --> * <!-- end-user-doc --> * @generated */ @SuppressWarnings("hiding") public static final String copyright = "Copyright 2006 Oracle"; //$NON-NLS-1$ /** * The default value of the '{@link #getMapSource() <em>Map Source</em>}' attribute. * <!-- begin-user-doc --> * <!-- end-user-doc --> * @see #getMapSource() * @generated * @ordered */ protected static final Map MAP_SOURCE_EDEFAULT = null; /** * The cached value of the '{@link #getMapSource() <em>Map Source</em>}' attribute. * <!-- begin-user-doc --> * <!-- end-user-doc --> * @see #getMapSource() * @generated * @ordered */ protected Map mapSource = MAP_SOURCE_EDEFAULT; /** * The default value of the '{@link #isImmutable() <em>Immutable</em>}' attribute. * <!-- begin-user-doc --> * <!-- end-user-doc --> * @see #isImmutable() * @generated * @ordered */ protected static final boolean IMMUTABLE_EDEFAULT = true; private static final Object MAP_TYPE_DESCRIPTOR_PROP_KEY = new Object(); /** * The cached value of the '{@link #isImmutable() <em>Immutable</em>}' attribute. * <!-- begin-user-doc --> * <!-- end-user-doc --> * @see #isImmutable() * @generated * @ordered */ protected boolean immutable = IMMUTABLE_EDEFAULT; /** * <!-- begin-user-doc --> * <!-- end-user-doc --> * @generated */ protected IMapTypeDescriptorImpl() { super(); } /** * <!-- begin-user-doc --> * @return the static eClass * <!-- end-user-doc --> * @generated */ protected EClass eStaticClass() { return SymbolPackage.Literals.IMAP_TYPE_DESCRIPTOR; } /** * <!-- begin-user-doc --> * @return the map source * <!-- end-user-doc --> * @generated */ public Map getMapSource() { return mapSource; } /** * <!-- begin-user-doc --> * @param newMapSource * <!-- end-user-doc --> * @generated */ public void setMapSource(Map newMapSource) { Map oldMapSource = mapSource; mapSource = newMapSource; if (eNotificationRequired()) eNotify(new ENotificationImpl(this, Notification.SET, SymbolPackage.IMAP_TYPE_DESCRIPTOR__MAP_SOURCE, oldMapSource, mapSource)); } /** * <!-- begin-user-doc --> * @return true if this map is immutable as defined in the java.util.Map * interface. * <!-- end-user-doc --> * @generated */ public boolean isImmutable() { return immutable; } /** * <!-- begin-user-doc --> * @param newImmutable * <!-- end-user-doc --> * @generated */ public void setImmutable(boolean newImmutable) { boolean oldImmutable = immutable; immutable = newImmutable; if (eNotificationRequired()) eNotify(new ENotificationImpl(this, Notification.SET, SymbolPackage.IMAP_TYPE_DESCRIPTOR__IMMUTABLE, oldImmutable, immutable)); } /* (non-Javadoc) * @see org.eclipse.jst.jsf.context.symbol.internal.impl.ITypeDescriptorImpl#getTypeSignature() * @generated NOT */ public String getTypeSignature() { // if the delegate has been set, use it if (eIsSet(SymbolPackage.IMAP_TYPE_DESCRIPTOR__TYPE_SIGNATURE_DELEGATE)) { return getTypeSignatureDelegate(); } // otherwise use Map return TypeConstants.TYPE_MAP; } public EList getInterfaceTypeSignatures() { return ECollections.EMPTY_ELIST; } public EList getSuperTypeSignatures() { return ECollections.EMPTY_ELIST; } /** * @see org.eclipse.jst.jsf.context.symbol.internal.impl.ITypeDescriptorImpl#getProperties() */ public EList getProperties() { final BasicEList list = new BasicEList(); final Map source = getMapSource(); if (source instanceof IMapSourceInfo) { if (!((IMapSourceInfo) source).hasChanged(MAP_TYPE_DESCRIPTOR_PROP_KEY)) { EList cachedList = (EList) ((IMapSourceInfo)source).getCachedValue(MAP_TYPE_DESCRIPTOR_PROP_KEY); if (cachedList != null) { return cachedList; } } } final Map segmentMap = processSegments(source); list.addAll(segmentMap.values()); if (source instanceof IMapSourceInfo) { ((IMapSourceInfo)source).putCachedValue(MAP_TYPE_DESCRIPTOR_PROP_KEY, list); } return list; } public EList getMethods() { // TODO: should this return the methods on a Map? return ECollections.EMPTY_ELIST; } /** * @generated NOT */ public IObjectSymbol getArrayElement() { return null; } /** * @generated NOT */ public boolean isArray() { // a map is never an array return false; } private Map processSegments(final Map source) { final Map segmentMap = new HashMap(); final Set<Map.Entry<String, Object>> entrySet = source.entrySet(); for (final Map.Entry<String, Object> entry : entrySet) { final String key = entry.getKey(); final String segments[] = fastTokenSplit(key); if (segments.length == 0) { continue; } IPropertySymbol property = (IPropertySymbol) segmentMap .get(segments[0]); if (property == null) { final Object propValue = entry.getValue(); property = SymbolFactory.eINSTANCE.createIPropertySymbol(); property.setName(segments[0]); ITypeDescriptor typeDesc = null; // TODO: need wrapper object to rationalize if (propValue != null) { if (propValue instanceof IType) { typeDesc = SymbolFactory.eINSTANCE .createIJavaTypeDescriptor2(); ((IJavaTypeDescriptor2) typeDesc) .setType((IType) propValue); } else if (propValue instanceof IInstanceSymbol) { typeDesc = ((IInstanceSymbol) propValue) .getTypeDescriptor(); } else if (propValue instanceof IPropertySymbol) { typeDesc = ((IPropertySymbol) propValue) .getTypeDescriptor(); } else { final String className = propValue.getClass().getName(); final String typeSignature = Signature .createTypeSignature(className, true); typeDesc = SymbolFactory.eINSTANCE .createIMapTypeDescriptor(); ((IMapTypeDescriptor) typeDesc) .setMapSource(new HashMap()); ((IMapTypeDescriptor) typeDesc) .setTypeSignatureDelegate(typeSignature); // inherit this descriptor's mutability ((IMapTypeDescriptor) typeDesc) .setImmutable(isImmutable()); property.setIntermediate(true); // set the property as // intermediate until we // find out different } property.setTypeDescriptor(typeDesc); property.setReadable(true); // is only writable if map is not immutable property.setWritable(!isImmutable()); } segmentMap.put(segments[0], property); } final ITypeDescriptor typeDesc = property.getTypeDescriptor(); if (typeDesc instanceof IMapTypeDescriptor) { if (segments.length == 1) { // TODO: not always allowed // ((IMapTypeDescriptor)typeDesc).getMapSource().put(null, // source.get(key)); // property is more than simply intermediate property.setIntermediate(false); } else { ((IMapTypeDescriptor) typeDesc).getMapSource().put( key.substring(key.indexOf('.') + 1), entry.getValue()); } } } return segmentMap; } /** * Based on measurements, this beats Pattern.split by 15-30% even with * a pre-compiled pattern. * * @param splitValue * @return the array of strings split by the '.' token */ private static String[] fastTokenSplit(final String splitValue) { if (splitValue == null || splitValue.length() == 0) { return new String[0]; } if (splitValue.indexOf('.') > -1) { return tokenizerSplit(splitValue); } return new String[] {splitValue}; } private static String[] tokenizerSplit(final String splitValue) { StringTokenizer stringTokenizer = new StringTokenizer(splitValue, "."); //$NON-NLS-1$ // initialize to a large size, since we're just going to truncate // it once at the end and want to reduce the chance of resize during // the loop. final List<String> splitValues = new ArrayList<String>(32); while (stringTokenizer.hasMoreTokens()) { splitValues.add(stringTokenizer.nextToken()); } return splitValues.toArray(new String[0]); } /** * <!-- begin-user-doc --> * @param featureID * @param resolve * @param coreType * @return the object for the feature id * <!-- end-user-doc --> * @generated */ public Object eGet(int featureID, boolean resolve, boolean coreType) { switch (featureID) { case SymbolPackage.IMAP_TYPE_DESCRIPTOR__MAP_SOURCE: return getMapSource(); case SymbolPackage.IMAP_TYPE_DESCRIPTOR__IMMUTABLE: return isImmutable() ? Boolean.TRUE : Boolean.FALSE; } return super.eGet(featureID, resolve, coreType); } /** * <!-- begin-user-doc --> * @param featureID * @param newValue * <!-- end-user-doc --> * @generated */ public void eSet(int featureID, Object newValue) { switch (featureID) { case SymbolPackage.IMAP_TYPE_DESCRIPTOR__MAP_SOURCE: setMapSource((Map)newValue); return; case SymbolPackage.IMAP_TYPE_DESCRIPTOR__IMMUTABLE: setImmutable(((Boolean)newValue).booleanValue()); return; } super.eSet(featureID, newValue); } /** * <!-- begin-user-doc --> * @param featureID * <!-- end-user-doc --> * @generated */ public void eUnset(int featureID) { switch (featureID) { case SymbolPackage.IMAP_TYPE_DESCRIPTOR__MAP_SOURCE: setMapSource(MAP_SOURCE_EDEFAULT); return; case SymbolPackage.IMAP_TYPE_DESCRIPTOR__IMMUTABLE: setImmutable(IMMUTABLE_EDEFAULT); return; } super.eUnset(featureID); } /** * <!-- begin-user-doc --> * @param featureID * @return true if is set * <!-- end-user-doc --> * @generated */ public boolean eIsSet(int featureID) { switch (featureID) { case SymbolPackage.IMAP_TYPE_DESCRIPTOR__MAP_SOURCE: return MAP_SOURCE_EDEFAULT == null ? mapSource != null : !MAP_SOURCE_EDEFAULT.equals(mapSource); case SymbolPackage.IMAP_TYPE_DESCRIPTOR__IMMUTABLE: return immutable != IMMUTABLE_EDEFAULT; } return super.eIsSet(featureID); } /** * <!-- begin-user-doc --> * @return the string representation * <!-- end-user-doc --> * @generated */ public String toString() { if (eIsProxy()) return super.toString(); StringBuffer result = new StringBuffer(super.toString()); result.append(" (mapSource: "); //$NON-NLS-1$ result.append(mapSource); result.append(", immutable: "); //$NON-NLS-1$ result.append(immutable); result.append(')'); return result.toString(); } } //IMapTypeDescriptorImpl