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 }