Skip to Content

If you read my The quik brouwn fox jamps ovrr the laizy dog you may notice that it is sometimes necessary to get DDIC type by name. In post mentioned I used a small workaround: all of the dictionary types necessary were loaded by WebDynpro framework itself during construction of context node’s attributes. However, this technique is not always applicable.

In my next post I’ll show how to create convenient user picker control using OVS (object value selector) with ICMIQuery. This type of OVS relies heavily on metadata provided by query object itself, and the most important part of this metadata is type information of input / result properties. Although I may apply “prototype” technique mentioned to get dictionary type information, it seriously invalidates elegancy and simplicity of solution.

Hence I start exploring possible ways to load DDIC type from any place of code. Obviously, that I may only rely either on singleton classes or so-called Booch-utility classes in WebDynpro framework. My first attempt was to create a singleton around some implementation of com.sap.dictionary.runtime.IDataProvider. Quickly I’d discovered DdJavaProvider in com.sap.dictionary.runtime package, but I had no luck applying it: neither standard types (like com.sap.dictionary.string) nor my custom simple types were visible to it. So the next two classes that grabs my attention was DdDictionaryPool and IBroker from the same package. After several trials and errors I came to solution described here.

So, here how the class works:

  • First we need to get reference to IBroker implementation.
    DdDictionaryPool provides method to create data type brokers by given class loader and locale.
  • Next, IBroker is used to get type by name.
    Corresponding method in IBroker implementation uses 2 parameters: logical dictionary and type name. As far as I understand, there are only 2 types of logical dictionaries available:
    1. local (or Java) dictionary associated with every WebDynpro project
    2. remote dictionaries that load type information from ABAP via JCo (do you remember that you are entering name of logical dictionary in Adaptive RFC model wizard?).

    Here we are interested only in local types, so we pass “java” as first argument (null also valid).

  • To avoid creating brokers for every type request, I cache them into hash map.
    Obviously, key in map resembles parameters necessary to create broker. But value is more interesting. Cache does not storing direct reference to broker, but rather wrap them into java.lang.ref.Reference object (see related Java API for more). Why this is done? Garbage collector may not discard object if normal references (“hard” references) exist. But if we wrap “hard” object reference into one of java.lang.ref.Reference implementations, then we get different behavior. So here I used SoftReference which provides desired functionality: if there are any hard references to broker it stays alive; if the only reference left is soft reference in my cache it is discarded. So this allows corresponding WD project to be un-deployed.
  • There are also convenient “cast” method that maps java primitive classes and primitive wrapper classes to ISimpleType.

So, the code should be self-explanatory after brief intro above:

/* * Created on 11.08.2005 */ package com.sap.sdn.samples.cmi; import java.lang.ref.SoftReference; import java.util.Locale; import java.util.Map; import java.util.HashMap; import java.util.IdentityHashMap; import java.util.Collections; import com.sap.dictionary.runtime.IBroker; import com.sap.dictionary.runtime.ISimpleType; import com.sap.dictionary.runtime.DdDictionaryPool; import com.sap.dictionary.runtime.DdException; /** * @author Valery_Silaev * */ final public class DictionaryTypes { private DictionaryTypes(){} public static ISimpleType getType ( final String typeName, final Locale l, final ClassLoader cl ) { try { return (ISimpleType)getBroker(cl, l).getDataType("java", typeName); } catch (final DdException ex) { throw new RuntimeException(ex); } } public static String getTypeName(final Class clazz) { if (null == clazz) throw new IllegalArgumentException ("Class parameter is null"); return (String)TYPES_MAP.get( clazz ); } public static ISimpleType cast(final Class type, final Locale locale) { final String typeName = getTypeName(type); if (null == typeName) throw new IllegalArgumentException ("Unnable to find corresponding DDIC type for class " + type.getName() ); return getType( typeName, locale, DictionaryTypes.class.getClassLoader() ); } private static synchronized IBroker getBroker(final ClassLoader cl, final Locale l) throws DdException { final BrokerKey key = new BrokerKey(cl, l); final SoftReference ref = (SoftReference)BROKERS.get(key); IBroker broker = null != ref ? (IBroker)ref.get() : null; if( null == broker ) { broker = DdDictionaryPool.getInstance().createBroker( cl, l); BROKERS.put( key, new SoftReference(broker) ); } return broker; } final private static class BrokerKey { final private Locale _l; final private ClassLoader _cl; final private int _h; private BrokerKey(final ClassLoader cl, final Locale l) { _l = l; _cl = cl; _h = 31 * cl.hashCode() + l.hashCode(); } final public int hashCode() { return _h; } final public boolean equals(final Object o) { if ( o.getClass() != BrokerKey.class ) return false; final BrokerKey k = (BrokerKey)o; return k._cl == _cl && k._l.equals( _l ); } } final private static Map BROKERS = new HashMap(); final private static Map TYPES_MAP; static { final Map map = new IdentityHashMap(20); map.put( boolean.class, "com.sap.dictionary.boolean" ); map.put( Boolean.class, "com.sap.dictionary.boolean" ); map.put( short.class, "com.sap.dictionary.short" ); map.put( Short.class, "com.sap.dictionary.short" ); map.put( int.class, "com.sap.dictionary.integer" ); map.put( Integer.class, "com.sap.dictionary.integer" ); map.put( long.class, "com.sap.dictionary.long" ); map.put( Long.class, "com.sap.dictionary.long" ); map.put( float.class, "com.sap.dictionary.float" ); map.put( Float.class, "com.sap.dictionary.float" ); map.put( double.class, "com.sap.dictionary.double" ); map.put( Double.class, "com.sap.dictionary.double" ); map.put( java.math.BigDecimal.class, "com.sap.dictionary.decimal" ); map.put( byte[].class, "com.sap.dictionary.binary" ); map.put( String.class, "com.sap.dictionary.string" ); map.put( java.sql.Time.class, "com.sap.dictionary.time" ); map.put( java.sql.Date.class, "com.sap.dictionary.date" ); map.put( java.sql.Timestamp.class, "com.sap.dictionary.timestamp" ); map.put( com.sap.tc.webdynpro.progmodel.api.WDVisibility.class, "com.sap.ide.webdynpro.uielementdefinitions.Visibility" ); TYPES_MAP = Collections.unmodifiableMap( map ); } }

Finally, I have to warn you: DdDictionaryPool class used is not documented. However, it resides in well-documented package and available both in NW04 and NW04s.

To report this post you need to login first.

Be the first to leave a comment

You must be Logged on to comment or reply to a post.

Leave a Reply