001    /*
002     * file ResourceSource.java
003     * 
004     * Licensed Materials - Property of IBM
005     * Restricted Materials of IBM - you are allowed to copy, modify and 
006     * redistribute this file as part of any program that interfaces with 
007     * IBM Rational CM API.
008     *
009     * com.ibm.rational.teamapi.scout.ResourceSource
010     *
011     * © Copyright IBM Corporation 2004, 2008.  All Rights Reserved.
012     * Note to U.S. Government Users Restricted Rights:  Use, duplication or 
013     * disclosure restricted by GSA ADP  Schedule Contract with IBM Corp.
014     */
015    package com.ibm.rational.teamapi.scout;
016    
017    import java.lang.reflect.Array;
018    import java.util.List;
019    
020    import javax.wvcm.PropertyRequestItem;
021    import javax.wvcm.WvcmException;
022    import javax.wvcm.PropertyNameList.PropertyName;
023    import javax.wvcm.PropertyRequestItem.PropertyRequest;
024    
025    import org.eclipse.swt.custom.BusyIndicator;
026    import org.eclipse.swt.widgets.Display;
027    import org.eclipse.ui.views.properties.IPropertyDescriptor;
028    import org.eclipse.ui.views.properties.IPropertySheetEntry;
029    import org.eclipse.ui.views.properties.PropertyDescriptor;
030    
031    import com.ibm.rational.wvcm.stp.StpLocation;
032    import com.ibm.rational.wvcm.stp.StpProperty;
033    import com.ibm.rational.wvcm.stp.StpPropertyException;
034    import com.ibm.rational.wvcm.stp.StpResource;
035    import com.ibm.rational.wvcm.stp.StpProperty.MetaPropertyName;
036    
037    
038    /**
039     * An implementation of IPropertySource for displaying the properties of a CM
040     * API Resource. ProperyName objects are used for the property identifiers.
041     */
042    public class ResourceSource
043        extends DefaultPropertySource
044    {
045        /**
046         * Requests all properties from the server and then constructs a property
047         * descriptor for each property returned. For efficiently, the descriptors
048         * are cached after the properties are read from the resource. The
049         * possibility of displaying stale data could be avoided by re-reading the
050         * properties each time the descriptors are requested.
051         *
052         * @return  An array of ResourcePropertyDescriptors, one for each property
053         *          of the resource represented by this object.
054         */
055        public IPropertyDescriptor[] getPropertyDescriptors()
056        {
057            if (m_descriptors == null) {
058                try {
059                    // At the top level some pseudo-resources are used to represent
060                    // requests for folder lists. Properties should not be requested
061                    // from these.
062                    StpLocation selector = m_resource.stpLocation();
063                    String      name = selector.getName();
064                    String      server = "";
065                    String      repo = selector.getRepo();
066    
067                    if ((name == null || name.length() == 0)
068                            && (repo == null || repo.length() == 0)
069                            && (server != null && server.length() > 0)) {
070                        return null;
071                    }
072    
073                    // This may take a while, so run it off the UI thread and
074                    // put up a wait cursor.
075                    final Display  display = Display.getCurrent();
076                    final Runnable longJob =
077                        new Runnable() {
078                            boolean m_done = false;
079    
080                            public void run()
081                            {
082                                Thread thread = new Thread(new Runnable() {
083                                            public void run()
084                                            {
085                                                try {
086                                                    m_resource =
087                                                        (StpResource)m_resource
088                                                        .doReadProperties(
089                                                            WANTED_PROPS);
090                                                } catch (WvcmException e) {
091                                                    e.printStackTrace();
092                                                }
093                                                m_done = true;
094                                            }
095                                        });
096                                thread.start();
097    
098                                while (!m_done) {
099                                    if (!display.readAndDispatch())
100                                        display.sleep();
101                                }
102                            }
103                        };
104    
105                    BusyIndicator.showWhile(display, longJob);
106    
107                    // Get a list of all the properties returned in the new proxy.
108                    StpProperty.List properties =
109                        (StpProperty.List)m_resource.getAllProperties();
110    
111                    m_descriptors = new IPropertyDescriptor[properties.size()];
112    
113                    for (int i = 0; i < m_descriptors.length; ++i) {
114                        Object property = properties.get(i);
115    
116                        // The StpProperty.List will contain a PropertyException if
117                        // the requested property could not be returned from the
118                        // resource; a StpProperty object otherwise. A different
119                        // variant of ResourcePropertyDescriptor is used for each
120                        // case.
121                        if (property instanceof StpProperty)
122                            m_descriptors[i] =
123                                new ResourcePropertyDescriptor((StpProperty)
124                                    property,
125                                    m_resource);
126                        else
127                            m_descriptors[i] =
128                                new ResourcePropertyDescriptor(
129                                    (StpPropertyException)property,
130                                    m_resource);
131                    }
132                } catch (Throwable ex) {
133                    ex.printStackTrace();
134                }
135            }
136    
137            return m_descriptors;
138        }
139    
140        /**
141         * Retrieves the value of a property from the resource proxy. Compound
142         * values are wrapped by a type-specific PropertySource for viewing the
143         * values.
144         *
145         * @param  id  The property identifier, which, in this case, is the
146         *             PropertyName of the CM API property.
147         *
148         * @return  Either a PropertySource (for compound values) or the value
149         *          itself.
150         */
151        public Object getPropertyValue(Object id)
152        {
153            Object val = m_resource.lookupProperty((PropertyName)id);
154    
155            return getPropertySource(val);
156        }
157    
158        /**
159         * Constructs a ResourceSource object for displaying the properties of a
160         * resource identified by a Resource proxy.
161         *
162         * @param  resource  A Resource proxy for the resource whose properties are
163         *                   to be displayed.
164         */
165        ResourceSource(StpResource resource)
166        {
167            m_resource = resource;
168        }
169    
170        /**
171         * The proxy for the resource whose properties are displayed by this source
172         */
173        protected StpResource m_resource;
174    
175        /** The cached property descriptors for the properties read. */
176        IPropertyDescriptor[] m_descriptors = null;
177    
178        /** The PropertyRequest used to request all properties from the resource */
179        static final PropertyRequest WANTED_PROPS =
180            new PropertyRequest(
181                new PropertyRequestItem[] {StpResource.ALL_PROPERTIES.nest(
182                        new PropertyRequestItem[] {StpProperty.VALUE.nest(
183                                new PropertyRequestItem[] {
184                                    StpProperty.NAME,
185                                    StpProperty.TYPE,
186                                    StpProperty.VALUE
187                                })})});
188    
189        /** The value used to flag properties with errors */
190        static final String[] ADVANCED_PROPERTY_FLAGS =
191            new String[] {IPropertySheetEntry.FILTER_ID_EXPERT};
192    
193        /**
194         * A PropertyDescriptor for CM API resource properties.
195         */
196        static class ResourcePropertyDescriptor
197            extends PropertyDescriptor
198        {
199            /**
200             * Constructs a PropertyDescriptor for a StpProperty successfully
201             * retrieved from a proxy. If the VALUE meta-property of the StpProperty
202             * is inaccessible, the property is marked as one for expert viewing
203             * only.
204             *
205             * @param  property  The StpProperty
206             * @param  parent  The resource from which the StpProperty came.
207             */
208            ResourcePropertyDescriptor(
209                StpProperty property,
210                StpResource parent)
211            {
212                super(property.getPropertyName(),
213                    property.getPropertyName().getName());
214                m_propertyName = property.getPropertyName();
215    
216                try {
217                    property.getValue();
218                } catch (WvcmException ex) {
219                    m_filter_flags = ADVANCED_PROPERTY_FLAGS;
220                }
221    
222                try {
223                    setDescription(property.getType() + " property of "
224                        + parent.location().string());
225                } catch (WvcmException ex) {
226                    setDescription("Untyped property of "
227                        + parent.location().string());
228                }
229            }
230    
231            /**
232             * Constructs a PropertyDescriptor for a PropertyException received
233             * while attempting to retrieve a StpProperty from a proxy. The property
234             * is marked as one for expert viewing only.
235             *
236             * @param  property  The PropertyException
237             * @param  parent  The resource from which the StpProperty came.
238             */
239            ResourcePropertyDescriptor(
240                StpPropertyException property,
241                StpResource          parent)
242            {
243                super(property.getPropertyName(),
244                    property.getPropertyName().getName());
245                m_propertyName = property.getPropertyName();
246                m_filter_flags = ADVANCED_PROPERTY_FLAGS;
247                setDescription("inaccessible property of "
248                    + parent.location().string());
249            }
250    
251            /**
252             * Returns the Namespace of the PropertyName for the property to use as
253             * a category for organizing the properties of the resource.
254             *
255             * @return  A String containing the simple name of the namespace of the
256             *          property name.
257             */
258            public String getCategory()
259            {
260                String category = m_propertyName.getNamespace();
261    
262                if (category == null)
263                    category = "WVCM";
264                else {
265                    int slash = category.lastIndexOf("/");
266    
267                    if (slash > 0)
268                        category = category.substring(slash + 1);
269                }
270    
271                return category;
272            }
273    
274            /**
275             * Returns ADVANCED_PROPERTY_FLAGS for properties that could not be read
276             * from the resource; null otherwise;
277             *
278             * @see  org.eclipse.ui.views.properties.PropertyDescriptor#getFilterFlags()
279             */
280            public String[] getFilterFlags()
281            {
282                return m_filter_flags;
283            }
284    
285            /** The PropertyName for the property */
286            PropertyName m_propertyName;
287    
288            /** The value of getFilterFlags() */
289            String[] m_filter_flags = super.getFilterFlags();
290        }
291    
292        /**
293         * A PropertySource for displaying properties whose value is a list.
294         */
295        static class ListSource
296            extends DefaultPropertySource
297        {
298            /**
299             * Constructs a new ListSource for a List value.
300             *
301             * @param  list  The value that is to be displayed by this
302             *               PropertySource
303             */
304            ListSource(List list)
305            {
306                m_list = list;
307            }
308    
309            /**
310             * Computes and returns an array of PropertyDescriptors, one descriptor
311             * per element of the list. An Integer object representing the ordinal
312             * position of the element in the list is used as the property id.
313             *
314             * @return  An array of PropertyDescriptors for the elements of the
315             *          ResourceList value of this property.
316             */
317            public IPropertyDescriptor[] getPropertyDescriptors()
318            {
319                IPropertyDescriptor[] result =
320                    new IPropertyDescriptor[m_list.size()];
321    
322                for (int i = 0; i < result.length; ++i) {
323                    String name = getDisplayName(m_list.get(i), i);
324    
325                    result[i] = new PropertyDescriptor(new Integer(i), name);
326                    ((PropertyDescriptor)result[i]).setDescription(m_list.getClass()
327                        .getName() + " item");
328                }
329    
330                return result;
331            }
332    
333            /**
334             * Retrieves the List item identified by a given property identifier.
335             *
336             * @param  id  An Integer representing the ordinal position of the item
337             *             in the list
338             *
339             * @return  The value at the given index, wrapped in a PropertySource if
340             *          the item is a composite object such as a Resource, List, or
341             *          Array.
342             */
343            public Object getPropertyValue(Object id)
344            {
345                return getPropertySource(m_list.get(((Integer)id).intValue()));
346            }
347    
348            /** The List that this PropertySource will be displaying */
349            List m_list;
350        }
351    
352        /**
353         * A PropertySource for displaying properties whose value is an array.
354         */
355        static class ArraySource
356            extends DefaultPropertySource
357        {
358            /**
359             * Constructs an ArraySource for an array value
360             *
361             * @param  array  The array to be displayed by the ArraySource.
362             */
363            ArraySource(Object array)
364            {
365                m_array = array;
366            }
367    
368            /**
369             * Computes and returns an array of PropertyDescriptors, one descriptor
370             * per element of the array. An Integer object representing the ordinal
371             * position of the element in the array is used as the property id.
372             *
373             * @return  An array of PropertyDescriptors for the elements of this
374             *          array-valued property.
375             */
376            public IPropertyDescriptor[] getPropertyDescriptors()
377            {
378                IPropertyDescriptor[] result =
379                    new IPropertyDescriptor[Array.getLength(m_array)];
380    
381                for (int i = 0; i < result.length; ++i) {
382                    String name = getDisplayName(Array.get(m_array, i), i);
383    
384                    result[i] = new PropertyDescriptor(new Integer(i), name);
385                }
386    
387                return result;
388            }
389    
390            /**
391             * Retrieves the array element identified by a given property
392             * identifier.
393             *
394             * @param  id  An Integer representing the index of the item in the
395             *             array
396             *
397             * @return  The value at the given index, wrapped in a PropertySource if
398             *          the item is a composite object such as a Resource, List, or
399             *          Array.
400             */
401            public Object getPropertyValue(Object id)
402            {
403                return getPropertySource(Array.get(
404                            m_array,
405                            ((Integer)id).intValue()));
406            }
407    
408            /** The array of values represented by this PropertySource */
409            Object m_array;
410        }
411    
412        /**
413         * A PropertySource for displaying properties whose value is a StpProperty.
414         */
415        static class PropertySource
416            extends DefaultPropertySource
417        {
418            /**
419             * Constructs a PropertySource for a StpProperty.
420             *
421             * @param  property  The StpProperty object to be displayed by this
422             *                   PropertySource
423             */
424            PropertySource(StpProperty property)
425            {
426                m_property = property;
427            }
428    
429            /**
430             * Computes and returns an array of PropertyDescriptors, one descriptor
431             * per meta-property defined by the StpProperty. A MetaPropertyName
432             * object is used as the property id.
433             *
434             * @return  An array of PropertyDescriptors for the meta-properties
435             *          defined for this property.
436             */
437            public IPropertyDescriptor[] getPropertyDescriptors()
438            {
439                MetaPropertyName[] metaProps = m_property.metaPropertyNames();
440                IPropertyDescriptor[] result =
441                    new IPropertyDescriptor[metaProps.length];
442    
443                for (int i = 0; i < result.length; ++i) {
444                    result[i] =
445                        new PropertyDescriptor(metaProps[i], metaProps[i].getName());
446                }
447    
448                return result;
449            }
450    
451            /**
452             * Retrieves the meta-property identified by a given property
453             * identifier.
454             *
455             * @param  id  A MetaPropertyName identifying a meta-property of the
456             *             StpProperty.
457             *
458             * @return  The value of the given meta-property, wrapped in a
459             *          PropertySource if the item is a composite object such as a
460             *          Resource, StpProperty, List, or Array.
461             */
462            public Object getPropertyValue(Object id)
463            {
464                try {
465                    MetaPropertyName<?> name = (MetaPropertyName<?>)id;
466                    Object prop = m_property.getMetaProperty(name);
467                    
468                    return getPropertySource(prop);
469                } catch (WvcmException ex) {
470                    return ex;
471                }
472            }
473    
474            /** The StpProperty being displayed by this PropertySource */
475            StpProperty<?> m_property;
476        }
477    
478        /**
479         * Selects a possible PropertySource for a given value based on the data
480         * type of the value. A PropertySource is used for a value that is a
481         * Resource, StpProperty, List (including ResourceList or StpProperty.List),
482         * or an array.
483         *
484         * @param  val  The value to be displayed
485         *
486         * @return  The input value or an appropriate PropertySource for it.
487         */
488        private static Object getPropertySource(Object val)
489        {
490            if (val != null) {
491                if (val instanceof List)
492                    val = new ListSource((List)val);
493                else if (val instanceof StpResource)
494                    val = new ResourceSource((StpResource)val);
495                else if (val.getClass().isArray())
496                    val = new ArraySource(val);
497                else if (val instanceof StpProperty)
498                    val = new PropertySource((StpProperty)val);
499                else if (val instanceof PropertyName) {
500                    PropertyName pn = (PropertyName)val;
501                    String       space = pn.getNamespace();
502    
503                    val = pn.getName() + (space == null ? "" : " in " + space);
504                }
505            }
506    
507            return val;
508        }
509    
510        /**
511         * Constructs an appropriate display name for an item in a compound value.
512         *
513         * @param  item  The item to be displayed
514         * @param  index  the index of the item in it's list.
515         *
516         * @return  A String containing a display name for the item.
517         */
518        private static String getDisplayName(
519            Object item,
520            int    index)
521        {
522            String name = "    " + Integer.toString(index);
523    
524            if (item instanceof StpResource)
525                name = ((StpResource)item).location().lastSegment();
526            else if (item instanceof StpProperty)
527                name = ((StpProperty)item).getPropertyName().getName();
528            else
529                name = name.substring(name.length() - 5);
530    
531            return name;
532        }
533    }