Subversion Repositories XServices

Rev

Rev 52 | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
30 brianR 1
/*
2
 *   Mylyn Connector for Serena Business Mashups
3
 * 	 Copyright 2010 Brian Rosenberger (Brutex Network)
4
 *
5
 *   Licensed under the Apache License, Version 2.0 (the "License");
6
 *   you may not use this file except in compliance with the License.
7
 *   You may obtain a copy of the License at
8
 *
9
 *       http://www.apache.org/licenses/LICENSE-2.0
10
 *
11
 *   Unless required by applicable law or agreed to in writing, software
12
 *   distributed under the License is distributed on an "AS IS" BASIS,
13
 *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
 *   See the License for the specific language governing permissions and
15
 *   limitations under the License.
16
 *
17
 *   Serena, TeamTrack and Serena Business Mashup are
18
 * 	 registered trademarks of SERENA Software Inc.
19
 */
20
 
21
package net.brutex.mylyn.sbmconnector.core;
22
 
23
import java.math.BigInteger;
24
import java.net.URL;
25
import java.util.ArrayList;
26
import java.util.Date;
39 brianR 27
import java.util.HashMap;
30 brianR 28
import java.util.Iterator;
29
import java.util.List;
39 brianR 30
import java.util.Map;
30 brianR 31
import java.util.StringTokenizer;
32
 
33
import javax.xml.namespace.QName;
34
import javax.xml.ws.BindingProvider;
35
 
36
import net.brutex.mylyn.sbmconnector.SBMConnectorPlugin;
31 brianR 37
import net.brutex.mylyn.sbmconnector.core.model.SBMField;
38
import net.brutex.mylyn.sbmconnector.core.model.SBMFieldTypes;
39
import net.brutex.mylyn.sbmconnector.core.model.SBMFieldValue;
30 brianR 40
import net.brutex.mylyn.sbmconnector.core.model.SBMNote;
41
import net.brutex.mylyn.sbmconnector.core.model.SBMStaticFields;
42
import net.brutex.sbm.wsclient.AEWebservicesFaultFault;
43
import net.brutex.sbm.wsclient.Aewebservices71;
44
import net.brutex.sbm.wsclient.Aewebservices71PortType;
45
import net.brutex.sbm.wsclient.Auth;
46
import net.brutex.sbm.wsclient.Field;
47
import net.brutex.sbm.wsclient.NameValue;
48
import net.brutex.sbm.wsclient.Note;
49
import net.brutex.sbm.wsclient.ObjectFactory;
52 brianR 50
import net.brutex.sbm.wsclient.ReportCategory;
51
import net.brutex.sbm.wsclient.ReportInfo;
52
import net.brutex.sbm.wsclient.ReportResult;
53
import net.brutex.sbm.wsclient.ReportsFilter;
54
import net.brutex.sbm.wsclient.RunReportResult;
30 brianR 55
import net.brutex.sbm.wsclient.TTItem;
56
import net.brutex.sbm.wsclient.TableData;
57
import net.brutex.sbm.wsclient.TableType;
31 brianR 58
import net.brutex.sbm.wsclient.Value;
30 brianR 59
 
60
import org.eclipse.core.runtime.CoreException;
61
import org.eclipse.mylyn.commons.net.AuthenticationCredentials;
62
import org.eclipse.mylyn.commons.net.AuthenticationType;
63
import org.eclipse.mylyn.tasks.core.RepositoryStatus;
64
import org.eclipse.mylyn.tasks.core.TaskRepository;
65
 
66
public class SBMClient {
67
 
68
	private Aewebservices71PortType port;
69
	private static final QName SERVICE_NAME = new QName("http://localhost:80/gsoap/aewebservices71.wsdl", "aewebservices71");
70
	private TaskRepository repository;
71
	private ObjectFactory of;
72
	private List<TableData> tables = new ArrayList<TableData>();
39 brianR 73
	private Map<String, List<SBMFieldValue>> validsets = new HashMap<String, List<SBMFieldValue>>();
30 brianR 74
 
32 brianR 75
	/**
76
	 * Instantiates a new SBM client.
77
	 * Creates new instance of the aewebservices71 {@link net.brutex.sbm.wsclient.ObjectFactory} and
78
	 * initializes web service endpoint from repository url.
79
	 *
80
	 * @param repository the repository
81
	 */
30 brianR 82
	public SBMClient(TaskRepository repository) {
83
		this.repository = repository;
84
		this.of = new ObjectFactory();
85
 
86
        URL wsdlURL = Aewebservices71.WSDL_LOCATION;
87
		wsdlURL = this.getClass().getResource("/META-INF/aewebservices71.wsdl");
88
        Aewebservices71 ss = new Aewebservices71(wsdlURL, SERVICE_NAME);
89
        port = ss.getAewebservices71();
90
        ((BindingProvider)port).getRequestContext().put(
91
        		BindingProvider.ENDPOINT_ADDRESS_PROPERTY,
92
        		repository.getRepositoryUrl());
93
	}
94
 
32 brianR 95
	/**
96
	 * Can authenticate checks if this SBMClient instance has proper authentication details
97
	 * set in its related repository. The check is done by invoking the GetUser web service.
98
	 *
99
	 * @return true, if successful
100
	 * @throws CoreException the core exception
101
	 */
30 brianR 102
	public boolean canAuthenticate() throws CoreException {
103
		try {
104
			port.getUser(getAuth(), repository.getCredentials(AuthenticationType.REPOSITORY).getUserName());
105
		} catch (AEWebservicesFaultFault e) {
106
			new CoreException(RepositoryStatus.createLoginError(
107
					repository.getRepositoryUrl(), SBMConnectorPlugin.PLUGIN_ID));
108
			return false;
109
		}
110
		return true;
111
	}
112
 
39 brianR 113
	public List<TTItem> getTTItemsByTable(String tablename, String sql_where) throws CoreException {
114
		return getTTItemsByTable(tablename, sql_where, false);
115
	}
116
 
32 brianR 117
	/**
118
	 * Gets the SBM items from a table. The result size is limited to 500 and the sorting is done
39 brianR 119
	 * by TS_ID descending.
32 brianR 120
	 *
121
	 * @param tablename the tablename
122
	 * @param sql_where the sql_where
123
	 * @return the tT items by table
124
	 * @throws CoreException the core exception
125
	 */
39 brianR 126
	public List<TTItem> getTTItemsByTable(String tablename, String sql_where, boolean getFullData) throws CoreException {
30 brianR 127
		List<TTItem> list = new ArrayList<TTItem>();
39 brianR 128
		String sections = "SECTION:FIXED";
129
		if(getFullData) sections = "SECTION:ALL";
30 brianR 130
		if(sql_where==null || sql_where.isEmpty()) sql_where = "TS_ID>0";
131
		try {
132
			list = port.getItemsByQueryWithName(
133
					getAuth(),
134
					tablename,
135
					"("+sql_where+")",
39 brianR 136
					"TS_ID desc",
137
					null,
138
					sections);
30 brianR 139
		} catch (AEWebservicesFaultFault e) {
39 brianR 140
			throw new CoreException(
30 brianR 141
					RepositoryStatus.createInternalError(
39 brianR 142
							SBMConnectorPlugin.PLUGIN_ID, e.getMessage(), e));
143
		}
30 brianR 144
		return list;
145
	}
146
 
52 brianR 147
	public List<TTItem> getTTItemsByReport(String reportuuid) throws CoreException {
148
		List<TTItem> list = new ArrayList<TTItem>();
149
		try {
150
			RunReportResult result = port.runReport(
151
					getAuth(), of.createQueryRange(), reportuuid, null, null, null, null, null, null,
152
					null, null, null, null, null);
153
			List<ReportResult> resultlist = result.getResult();
154
			for(ReportResult r : resultlist) {
155
				list.add(port.getItem( getAuth(), r.getItemId().getValue(), null));
156
			}
157
		} catch (AEWebservicesFaultFault e) {
158
			throw new CoreException(
159
					RepositoryStatus.createInternalError(
160
							SBMConnectorPlugin.PLUGIN_ID, e.getMessage(), e));
161
		}
162
		return list;
163
	}
164
 
165
 
166
	public List<ReportInfo> getReportList(String solutionname) throws CoreException {
167
		ReportsFilter filter = of.createReportsFilter();
168
		List<ReportInfo> reportlist = new ArrayList<ReportInfo>();
169
		filter.setSolutionName(of.createSolutionDataName(solutionname));
170
		filter.setReportCategory(ReportCategory.USERREPORTS); //Limit this for now, because we execute by uuid only
171
		try {
172
			reportlist = port.getReports(getAuth(), null, filter).getReport();
173
		} catch (AEWebservicesFaultFault e) {
174
			throw new CoreException(
175
					RepositoryStatus.createInternalError(
176
							SBMConnectorPlugin.PLUGIN_ID, e.getMessage(), e));
177
		}
178
 
179
		return reportlist;
180
	}
181
 
42 brianR 182
	public List<String> getResultCount(String tablename, String sql) throws CoreException {
39 brianR 183
		List<TTItem> list = new ArrayList<TTItem>();
42 brianR 184
		List<String> idlist = new ArrayList<String>();
39 brianR 185
		try {
186
			list = port.getItemsByQueryWithName(
187
					getAuth(),
188
					tablename,
189
					"("+sql+")",
190
					"TS_ID desc",
191
					null,
192
					"SECTION:NONE");
193
		} catch (AEWebservicesFaultFault e) {
194
			throw new CoreException(
195
					RepositoryStatus.createInternalError(
196
							SBMConnectorPlugin.PLUGIN_ID, e.getMessage(), e));
197
		}
42 brianR 198
		for (TTItem item : list) {
199
			idlist.add(item.getGenericItem().getValue().getItemID().getValue());
200
		}
201
		return idlist;
39 brianR 202
	}
203
 
32 brianR 204
	/**
205
	 * Gets a SBM item specified by its internal identifier ([tableid:recordid])
206
	 *
207
	 * @param itemid the itemid
208
	 * @return the tT item
209
	 */
30 brianR 210
	public TTItem getTTItem(String itemid) {
39 brianR 211
		int pos1;
212
		int pos2;
213
		pos1 = itemid.lastIndexOf("[")+1;
214
		pos2 = itemid.lastIndexOf("]");
215
		itemid = itemid.substring(pos1, pos2);
30 brianR 216
		TTItem item = of.createTTItem();
217
			try {
218
				item = port.getItem(getAuth(), itemid, null);
219
			} catch (AEWebservicesFaultFault e) {
220
				new CoreException(
221
						RepositoryStatus.createInternalError(
222
								SBMConnectorPlugin.PLUGIN_ID, e.getFaultInfo(), e));
223
			}
224
			return item;
225
	}
226
 
227
 
228
 
229
	private Auth getAuth() {
230
		Auth auth = of.createAuth();
231
		AuthenticationCredentials credentials = repository.getCredentials(AuthenticationType.REPOSITORY);
232
		auth.setUserId(of.createAuthUserId(credentials.getUserName()));
233
		auth.setPassword(of.createAuthPassword(credentials.getPassword()));
234
		return auth;
235
	}
236
 
31 brianR 237
	/**
238
	 * Gets the field value for a system generic field.
239
	 *
240
	 * @param ttitem the ttitem
241
	 * @param fieldname the fieldname
242
	 * @return the static field value
243
	 */
244
	public String getStaticFieldValue(TTItem ttitem, String fieldname) {
30 brianR 245
		if(fieldname.equals(SBMStaticFields.SUBMITDATE.getValue())) {
246
			Date date = ttitem.getCreateDate().getValue().toGregorianCalendar().getTime();
247
			return String.valueOf(date.getTime());
248
		}
249
		if(fieldname.equals(SBMStaticFields.LASTMODIFIEDDATE.getValue())) {
250
			return String.valueOf(ttitem.getModifiedDate().getValue().toGregorianCalendar().getTimeInMillis());
251
		}
252
		if(fieldname.equals("TITLE")) {
253
			if(ttitem.getTitle()==null || ttitem.getTitle().isNil()) return "";
254
			return ttitem.getTitle().getValue();
255
		}
256
		if(fieldname.equals(SBMStaticFields.ISSUEID.getValue())) {
257
			if(ttitem.getGenericItem()==null || ttitem.getGenericItem().getValue().getItemName()==null) {
258
				return "";
259
			}
260
			return ttitem.getGenericItem().getValue().getItemName().getValue();
261
		}
262
		if(fieldname.equals("ISSUETYPE")) {
263
			if(ttitem.getItemType()==null || ttitem.getItemType().isNil()) return "";
264
			return ttitem.getItemType().getValue();
265
		}
266
		if(fieldname.equals(SBMStaticFields.STATE.getValue())) {
267
			if(ttitem.getState()==null || ttitem.getState().isNil()) return "";
268
			return ttitem.getState().getValue();
269
		}
270
		if(fieldname.equals(SBMStaticFields.ID.getValue())) {
34 brianR 271
			return ttitem.getGenericItem().getValue().getItemName().getValue()+
272
			" ["+ttitem.getGenericItem().getValue().getItemID().getValue()+"]";
30 brianR 273
		}
274
		if(fieldname.equals(SBMStaticFields.PROJECTID.getValue())) {
275
			if(ttitem.getClassification() ==null || ttitem.getClassification().isNil()) return "";
276
			return ttitem.getClassification().getValue();
277
		}
278
		if(fieldname.equals(SBMStaticFields.PROJECTUUID.getValue())) {
279
			if(ttitem.getClassificationUUID()==null || ttitem.getClassificationUUID().isNil()) return "";
280
			return ttitem.getClassificationUUID().getValue();
281
		}
282
		if(fieldname.equals("DESCRIPTION")) {
283
			if(ttitem.getDescription() == null || ttitem.getDescription().isNil()) return "";
284
			return ttitem.getDescription().getValue();
285
		}
286
		if(fieldname.equals(SBMStaticFields.SUBMITTER.getValue())) {
287
			if(ttitem.getCreatedBy()==null || ttitem.getCreatedBy().isNil()) return "";
288
			return ttitem.getCreatedBy().getValue();
289
		}
290
		if(fieldname.equals(SBMStaticFields.SUBMITDATE.getValue())) {
291
			return String.valueOf(ttitem.getCreateDate().getValue().toGregorianCalendar().getTimeInMillis());
292
		}
293
		if(fieldname.equals(SBMStaticFields.LASTMODIFIER.getValue())) {
294
			if(ttitem.getModifiedBy()==null || ttitem.getModifiedBy().isNil()) return "";
295
			return ttitem.getModifiedBy().getValue();
296
		}
297
		if(fieldname.equals(SBMStaticFields.LASTMODIFIEDDATE.getValue())) {
298
			return String.valueOf(ttitem.getModifiedDate().getValue().toGregorianCalendar().getTimeInMillis());
299
		}
300
		if(fieldname.equals(SBMStaticFields.ACTIVEINACTIVE.getValue())) {
301
			return ttitem.getActiveInactive().getValue();
302
		}
303
		if(fieldname.equals(SBMStaticFields.OWNER.getValue())) {
304
			return ttitem.getOwner().getValue();
305
		}
306
		if(fieldname.equals(SBMStaticFields.ITEMURL.getValue())) {
307
			return ttitem.getUrl().getValue();
308
		}
309
		if(fieldname.equals(SBMStaticFields.UUID.getValue())) {
310
			return ttitem.getGenericItem().getValue().getItemUUID().getValue();
311
		}
312
		if(fieldname.equals(SBMStaticFields.CLOSEDATE.getValue())) {
313
			Iterator<NameValue> list = ttitem.getExtendedFieldList().iterator();
314
			while (list.hasNext()) {
315
				NameValue field = list.next();
316
				if(field.getName().getValue().equals("CLOSEDATE")) {
317
					return field.getValue().getValue().getInternalValue().getValue();
318
				}
319
			}
320
		}
321
		if(fieldname.equals(SBMStaticFields.LASTSTATECHANGEDATE.getValue())) {
322
			Iterator<NameValue> list = ttitem.getExtendedFieldList().iterator();
323
			while (list.hasNext()) {
324
				NameValue field = list.next();
325
				if(field.getName().getValue().equals("LASTSTATECHANGEDATE")) {
326
					return field.getValue().getValue().getInternalValue().getValue();
327
				}
328
			}
329
		}
330
		if(fieldname.equals(SBMStaticFields.SECONDARYOWNER.getValue())) {
331
			Iterator<NameValue> list = ttitem.getExtendedFieldList().iterator();
332
			while (list.hasNext()) {
333
				NameValue field = list.next();
334
				if(field.getName().getValue().equals("SECONDARYOWNER")) {
335
					return field.getValue().getValue().getInternalValue().getValue();
336
				}
337
			}
338
		}
339
		if(fieldname.equals(SBMStaticFields.LASTSTATECHANGER.getValue())) {
340
			Iterator<NameValue> list = ttitem.getExtendedFieldList().iterator();
341
			while (list.hasNext()) {
342
				NameValue field = list.next();
343
				if(field.getName().getValue().equals("LASTSTATECHANGER")) {
344
					return field.getValue().getValue().getDisplayValue().getValue();
345
				}
346
			}
347
		}
348
 
349
		return "UNKNOWN";
350
	}
351
 
32 brianR 352
	/**
353
	 * Gets the field label. The SBM item is used to determine the table id of
354
	 * the table where this field is in.
355
	 *
356
	 * @param ttitem the ttitem
357
	 * @param fieldname the fieldname
358
	 * @return the field label
359
	 */
30 brianR 360
	public String getFieldLabel(TTItem ttitem, String fieldname) {
31 brianR 361
		refreshTables();
30 brianR 362
		String itemid = ttitem.getGenericItem().getValue().getItemID().getValue();
363
		String tableid = new StringTokenizer(itemid, ":").nextToken();
364
		for (TableData table : tables) {
365
			if (String.valueOf(table.getTableID().intValue()).equals(tableid)) {
366
				Iterator<Field> iter = table.getFieldList().iterator();
367
				while(iter.hasNext()) {
368
					Field f = iter.next();
369
					if(f.getName().getValue().equals(fieldname)) {
370
						return f.getDisplayName().getValue();
371
					}
372
				}
373
				break;
374
			}
375
		}
39 brianR 376
	return fieldname; //field has not been found
30 brianR 377
	}
378
 
31 brianR 379
	/**
380
	 * Gets the table database name.
381
	 *
382
	 * @param ttitem the ttitem
383
	 * @return the table name or null in case table is not found
384
	 */
385
	public String getTableName(TTItem ttitem) {
386
		refreshTables();
387
		String itemid = ttitem.getGenericItem().getValue().getItemID().getValue();
388
		String tableid = new StringTokenizer(itemid, ":").nextToken();
389
		for (TableData table : tables) {
390
			if (String.valueOf(table.getTableID().intValue()).equals(tableid)) {
391
				return table.getName().getValue();
392
			}
393
		}
394
		return null;
395
	}
396
 
32 brianR 397
	/**
398
	 * Gets the notes attached to a SBM item.
399
	 *
400
	 * @param ttitem the ttitem
401
	 * @return the notes
402
	 */
30 brianR 403
	public List<SBMNote> getNotes(TTItem ttitem) {
404
		List<SBMNote> notes = new ArrayList<SBMNote>();
405
		Iterator<Note> iter = ttitem.getNoteList().iterator();
406
		while(iter.hasNext()) {
407
			Note n = iter.next();
408
			SBMNote note = new SBMNote("sbm_user",
409
					n.getTitle().getValue()+"\n"+n.getNote().getValue(),
410
					n.getModificationDateTime().toGregorianCalendar().getTime(),
411
					n.getId().toString());
412
			notes.add(note);
413
		}
414
		return notes;
415
	}
416
 
31 brianR 417
 
418
	/**
419
	 * Gets the names of all available primary tables.
420
	 * A table name is a unique reference within one SBM environment, thus can be
421
	 * used as a key.
422
	 *
423
	 * @return the primary table names as a list
424
	 */
30 brianR 425
	public List<String> getPrimaryTables() {
31 brianR 426
		refreshTables();
30 brianR 427
		List<String> table_names = new ArrayList<String>();
31 brianR 428
		for (TableData table : tables) {
429
			table_names.add(table.getName().getValue());
430
		}
431
		return table_names;
432
	}
433
 
434
	/**
435
	 * Refresh table specifications from SBM web service. This
436
	 * is only done once per SBMClient instance.
437
	 */
438
	private void refreshTables() {
30 brianR 439
		if (tables.isEmpty()) {
440
			try {
31 brianR 441
				//currently we limit this to primary tables
30 brianR 442
				tables = port.getTables(getAuth(), null, TableType.PRIMARY_TABLE);
443
			} catch (AEWebservicesFaultFault e) {
444
				new CoreException(
445
						RepositoryStatus.createInternalError(
446
								SBMConnectorPlugin.PLUGIN_ID, e.getFaultInfo(), e));
447
			}
448
		}
31 brianR 449
	}
450
 
451
	/**
452
	 * Gets the fields for a primary table
453
	 *
454
	 * @param tablename the table database name
455
	 * @return the fields, empty when table does not exist
456
	 */
457
	public List<SBMField> getFields(String tablename) {
458
		refreshTables();
459
		List<SBMField> fields = new ArrayList<SBMField>();
30 brianR 460
		for (TableData table : tables) {
31 brianR 461
			if(table.getName().getValue().equals(tablename)) {
462
				Iterator<Field> iter = table.getFieldList().iterator();
463
				while(iter.hasNext()) {
464
					Field f = iter.next();
465
					SBMField nf = new SBMField(
466
							SBMFieldTypes.fromValue(f.getFieldType().value()),
467
							tablename,
468
							f.getDisplayName().getValue(),
469
							f.getName().getValue());
470
					fields.add(nf);
471
				}
472
				break;
473
			}
30 brianR 474
		}
31 brianR 475
		return fields;
30 brianR 476
	}
31 brianR 477
 
478
	/**
479
	 * Gets the field value for custom defined field.
480
	 * (those from &lt;extendedFieldList&gt;)
481
	 *
482
	 * @param ttitem the ttitem
483
	 * @param fieldname the fieldname
484
	 * @return the field value or null if the field is not found
485
	 */
486
	public SBMFieldValue getFieldValue(TTItem ttitem, String fieldname) {
487
		SBMFieldValue value;
488
		Iterator<NameValue> fs = ttitem.getExtendedFieldList().iterator();
489
		while(fs.hasNext()) {
490
			NameValue nv = fs.next();
491
			if(nv.getName().getValue().equals(fieldname)) {
492
				if (nv.getValue()!=null && !nv.getValue().isNil()) {
493
					value = new SBMFieldValue(
494
							nv.getValue().getValue().getInternalValue().getValue(),
495
							nv.getValue().getValue().getDisplayValue().getValue());
496
					return value;
497
				}
498
			}
499
		}
500
		return null;
501
	}
502
 
503
	/**
504
	 * Gets the field values for custom defined, multi type field.
505
	 * (those from &lt;extendedFieldList&gt;)
506
	 *
507
	 * @param ttitem the ttitem
508
	 * @param fieldname the fieldname
509
	 * @return the list of field values
510
	 */
511
	public List<SBMFieldValue> getFieldValues(TTItem ttitem, String fieldname) {
512
		List<SBMFieldValue> values = new ArrayList<SBMFieldValue>();
513
		Iterator<NameValue> fs = ttitem.getExtendedFieldList().iterator();
514
		while(fs.hasNext()) {
515
			NameValue nv = fs.next();
516
			if(nv.getName().getValue().equals(fieldname)) {
517
				if (nv.getValues()!=null && !nv.getValues().isEmpty()) {
518
					Iterator<Value> nvv = nv.getValues().iterator();
519
					while(nvv.hasNext()) {
520
						Value nvv_value = nvv.next();
521
						SBMFieldValue value = new SBMFieldValue(
522
							nvv_value.getInternalValue().getValue(),
523
							nvv_value.getDisplayValue().getValue());
524
						values.add(value);
525
					}
526
					return values;
527
				}
528
			}
529
		}
530
		return values;
531
	}
34 brianR 532
 
533
	public List<SBMFieldValue> getValidSet(String tablename, String fieldname) {
39 brianR 534
		if(validsets.containsKey(tablename+":"+fieldname)) return validsets.get(tablename+":"+fieldname);
34 brianR 535
		List<SBMFieldValue> list = new ArrayList<SBMFieldValue>();
536
		List<TTItem> ttlist = new ArrayList<TTItem>();
537
		String sql = "TS_ID in (select max(TS_ID) from "+tablename+" group by ts_"+fieldname+")";
538
		try {
539
			ttlist = getTTItemsByTable(tablename, sql);
540
		} catch (CoreException e) {
541
			new CoreException(
542
					RepositoryStatus.createInternalError(
543
							SBMConnectorPlugin.PLUGIN_ID, e.getMessage(), e));
544
		}
545
		for(TTItem ttitem : ttlist) {
546
			list.add(getFieldValue(ttitem, fieldname));
547
		}
39 brianR 548
		validsets.put(tablename+":"+fieldname, list);
34 brianR 549
		return list;
550
	}
30 brianR 551
}